SHOW:
|
|
- or go back to the newest paste.
| 1 | - | IM GAY |
| 1 | + | |
| 2 | ||
| 3 | /** | |
| 4 | * @author 3nvisi0n | |
| 5 | * @copyright 2011 | |
| 6 | * | |
| 7 | * This is just a basic version of my Xat Bot you can build upon to add the feature you want. | |
| 8 | * | |
| 9 | */ | |
| 10 | set_time_limit(0);//No time out | |
| 11 | $bot = new BasicXatBot(); | |
| 12 | $roomID = 88973610;//Don't know how to get this ID? goto xat.com/ROOM_YOU_WANT_BOT_IN and View Source(Firefox: Ctrl+U, Internet Explorer: View>Source) Look for "flashvars="id=#########&..." the ID is the number you want | |
| 13 | $bot->connect("174.36.242.26","10024"); //Connect to XAT...this IP will change as necessary automatically depending on the room you want to join.
| |
| 14 | $bot->join($roomID); | |
| 15 | while(true){
| |
| 16 | if($bot->read()=='DIED') {
| |
| 17 | $bot->connect("174.36.242.26","10024");
| |
| 18 | $bot->join($roomID); | |
| 19 | } | |
| 20 | } | |
| 21 | ||
| 22 | ||
| 23 | class BasicXatBot {
| |
| 24 | private $soc; //Socket for bot | |
| 25 | private $debug = false; //Used to toggle debugging output. | |
| 26 | private $packet; //Stores information about the last recieved packet of each kind | |
| 27 | private $userInfo; //Stores User information | |
| 28 | ||
| 29 | //If you don't know where to get these you should probably not be trying to make your own bot. | |
| 30 | //Go download WPE Pro and check out the packets XAT sends and learn about how XAT works. | |
| 31 | //The UserID and K Value are the source or the 'old falsh' error(if you get it) make sure you get these values from a REGISTERED account | |
| 32 | ||
| 33 | private $userID = "37007701"; //The Bot's UserID | |
| 34 | private $k = "3607438505"; //The Bot's K value | |
| 35 | ||
| 36 | //Bot Account Settings | |
| 37 | private $name = "XBot"; //The display name the bot will use | |
| 38 | private $avatar = -1; //The Avatar value for the bot, this can be an id number or an image url. | |
| 39 | private $homepage = ""; //The bot's homepage link. | |
| 40 | private $roomID; //This gets set in code, don't touch it here. just used ->join(ID) | |
| 41 | ||
| 42 | ||
| 43 | /** | |
| 44 | * This is where everything the bot does needs to happen, this is the only default function you should need to edit | |
| 45 | * @param $event The event that just occured(and thus needs to be handled) | |
| 46 | * @param $data Any data relating to this event. | |
| 47 | */ | |
| 48 | function handleEvent($event,$data) {
| |
| 49 | $info = $this->getUserArray($data['id']); | |
| 50 | switch($event) {
| |
| 51 | case 'userJoined': | |
| 52 | /* $data['id'] Has the ID of the user who just joined | |
| 53 | $data['old'] Sometimes XAT sends packets that are not current(for example when you join a room, old ==true for all users who are already in the room when you join, but still this event is handled as thought they just joined */ | |
| 54 | ||
| 55 | //Do whever you want with users joining here... | |
| 56 | echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) has just joined.\n"; | |
| 57 | break; | |
| 58 | case 'userLeft': | |
| 59 | - | private $userID = "351599155"; //The Bot's UserID |
| 59 | + | |
| 60 | echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) has just left.\n"; | |
| 61 | break; | |
| 62 | case 'privateMessage': | |
| 63 | /* $data['id'] The ID of the user that just left. | |
| 64 | $data['message'] The message sent to you as a PM */ | |
| 65 | echo "[PM] ".((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n"; | |
| 66 | ||
| 67 | //Example of a private message command | |
| 68 | $command = explode(' ',$data['message'],2); //First parse the first word out see if it is a command...
| |
| 69 | //[0] has first word [1] has everything else | |
| 70 | if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
| |
| 71 | switch($command[0]) {
| |
| 72 | case '!say': | |
| 73 | case '!speak': | |
| 74 | case '!talk': | |
| 75 | $this->sendPrivateMessage($command[1],$data['id']); | |
| 76 | break; | |
| 77 | case '!info': | |
| 78 | $this->sendPrivateMessage('I am a bot ^_^',$data['id']);
| |
| 79 | break; | |
| 80 | } | |
| 81 | } | |
| 82 | break; | |
| 83 | case 'privateChat': | |
| 84 | /* $data['id'] The ID of the user that just left. | |
| 85 | $data['message'] The message sent to you as a PC */ | |
| 86 | echo "[PC] ".((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n"; | |
| 87 | ||
| 88 | //Example of a private chat command | |
| 89 | $command = explode(' ',$data['message'],2); //First parse the first word out see if it is a command...
| |
| 90 | //[0] has first word [1] has everything else | |
| 91 | if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
| |
| 92 | switch($command[0]) {
| |
| 93 | case '!info': | |
| 94 | $this->sendPrivateChat('I am a bot ^_^',$data['id']);
| |
| 95 | break; | |
| 96 | } | |
| 97 | } | |
| 98 | break; | |
| 99 | case 'message': | |
| 100 | /* $data['id'] The ID of the user | |
| 101 | $data['old'] See $data['old'] under userJoined | |
| 102 | $data['message'] The message sent to main chat */ | |
| 103 | echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n"; | |
| 104 | ||
| 105 | //How to do main chat commands: | |
| 106 | if($data['old']) return; //Old message | |
| 107 | $command = explode(' ',trim($data['message']),2); //First parse the first word out see if it is a command...
| |
| 108 | //[0] has first word [1] has everything else | |
| 109 | if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
| |
| 110 | switch($command[0]) {
| |
| 111 | case '!say': | |
| 112 | case '!speak': | |
| 113 | case '!talk': | |
| 114 | //Multiple cases lead to the same code being run... | |
| 115 | $this->sendMessage($command[1]); | |
| 116 | break; | |
| 117 | case '!slap': | |
| 118 | case '!slaps': | |
| 119 | case '!hit': | |
| 120 | $this->sendMessage(((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])." slaps $command[1] around a bit with a large trout."); | |
| 121 | break; | |
| 122 | case '!avatar'://steal an avatar via !avatar USER_ID | |
| 123 | $user = $this->getUserArray($command[1]); | |
| 124 | $this->sendMessage(str_replace('(','( ',$user['avatar']));
| |
| 125 | break; | |
| 126 | case '!info': | |
| 127 | $this->sendMessage('I am a bot ^_^',$data['id']);
| |
| 128 | break; | |
| 129 | case '!yt': | |
| 130 | case '!youtube': | |
| 131 | case '!y': | |
| 132 | if(trim($command[1])=='') $this->sendMessage("Usage: $command[0] SEARCH TERMS HERE");
| |
| 133 | else {
| |
| 134 | //Yeah I know I don't really need urlencode() i could just replace spaces with + but this is a bit more secure. | |
| 135 | $res = $this->get('http://www.youtube.com/results?search_query='.urlencode(preg_replace("/[^A-Za-z0-9 !.,:[]\s\s+]/",'',$command[1])));
| |
| 136 | for($i=0;$i<3;$i++) {
| |
| 137 | $msg=$this->getBetween($res, '<h3>', '</h3>'); | |
| 138 | $res = str_replace('<h3>'.$msg,'</h3>',$res);
| |
| 139 | $url = "http://www.youtube.com".$this->getBetween($msg,'href="', '"'); | |
| 140 | $title = @ereg_replace('[^A-Za-z0-9 -()[]<>{}&@]','',$this->getBetween($msg,'title="', '"'));
| |
| 141 | $this->sendMessage($title." - $url"); | |
| 142 | sleep(1);//Xat won't let us send more than 1 message per second, it ignores anything faster. | |
| 143 | } | |
| 144 | } | |
| 145 | break; | |
| 146 | case '!g': | |
| 147 | case '!google': | |
| 148 | $res = $this->get('http://www.google.com/search?hl=en&source=hp&biw=&bih=&q='.str_replace(' ','+',$command[1]).'&btnG=Google+Search',true);
| |
| 149 | for($i=0;$i<3;$i++) {
| |
| 150 | $msg=$this->getBetween($res, '<h3 class="r"><a href="', '"'); | |
| 151 | $res = str_replace('<h3 class="r"><a href="'.$msg,'',$res);
| |
| 152 | $this->sendMessage($msg); | |
| 153 | sleep(1); | |
| 154 | } | |
| 155 | } | |
| 156 | } | |
| 157 | break; | |
| 158 | ||
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | ||
| 163 | ||
| 164 | /* ****************************************************** */ | |
| 165 | /* *YOU SHOULD NOT NEED TO EDIT ANYTHING AFTER THIS LINE* */ | |
| 166 | /* ****************************************************** */ | |
| 167 | /** | |
| 168 | * Connects to a given ip on the given port | |
| 169 | * @param $ip The IP to connect to. | |
| 170 | * @param $port The port on the IP to connect to. | |
| 171 | */ | |
| 172 | function connect($ip, $port) {
| |
| 173 | if($this->soc!=null) socket_close($this->soc); | |
| 174 | $this->soc = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); | |
| 175 | if(!$this->soc) die(socket_strerror(socket_last_error($this->soc))); | |
| 176 | if(!socket_connect($this->soc,$ip,$port)) die("Could not connect.");
| |
| 177 | } | |
| 178 | ||
| 179 | /** | |
| 180 | * Writes the given message to the object socket($this->soc) | |
| 181 | * @param $message The packet to send. | |
| 182 | */ | |
| 183 | function send($message) {
| |
| 184 | if($this->debug)echo "->>\t$message\n"; | |
| 185 | socket_write($this->soc, $message."\0", strlen($message)+1); | |
| 186 | } | |
| 187 | ||
| 188 | ||
| 189 | /** | |
| 190 | * Reads a message from the socket, will read until entire message has been recieved or connection closes. | |
| 191 | * @param $parse Used for recursive calls to tell the function not to parse a partial packet | |
| 192 | */ | |
| 193 | function read($parse=true) {
| |
| 194 | $res = rtrim(socket_read($this->soc, 4096)); | |
| 195 | if($this->debug)echo "<<-\t$res\n"; | |
| 196 | if(!$res) {
| |
| 197 | return "DIED"; //Used to gracefully handle a closed socket | |
| 198 | } | |
| 199 | if($res{strlen($res)-1}!='>') { $res.=$this->read(false);} //Recursive call for messages split over several packets.
| |
| 200 | if($parse)$this->parse($res); | |
| 201 | return $res; | |
| 202 | } | |
| 203 | ||
| 204 | /** | |
| 205 | * Parses the recieved packets into their message and types. | |
| 206 | * @param $packet The packet recieved. | |
| 207 | */ | |
| 208 | function parse($packet) {
| |
| 209 | if(substr_count($packet,'>')>1) $packet = explode('/>',$packet);//If necessary split the packet into individual messages
| |
| 210 | foreach((Array)$packet as $p) {
| |
| 211 | $p = trim($p); | |
| 212 | if(strlen($p)<5) return;//garbage data | |
| 213 | $type = trim(strtolower(substr($p,1,strpos($p.' ',' '))));//packet type | |
| 214 | $p = trim(str_replace("<$type",'',str_replace('/>','',$p)));//remove details so it is just the info to be parsed
| |
| 215 | parse_str(str_replace('"','',str_replace('" ','&',str_replace('="','=',str_replace('&','__38',$p)))),$this->packet[$type]);
| |
| 216 | foreach($this->packet[$type] as $k=>$v) {
| |
| 217 | $this->packet[$type][$k] = str_replace('__38','&',$v); //htmlspecial chars are protected instead of being parsed
| |
| 218 | } | |
| 219 | $this->handle($type,$p); | |
| 220 | } | |
| 221 | } | |
| 222 | ||
| 223 | /** | |
| 224 | * This is the inital handler for the packets, parses them and sends them off to their respective function to be handled further. | |
| 225 | * @param $type The character code indicating the type of data within the message. | |
| 226 | * @param $message The data the message contains. | |
| 227 | */ | |
| 228 | function handle($type,$msg) {
| |
| 229 | switch($type) {
| |
| 230 | case 'gp': | |
| 231 | if(isset($this->packet['gp']['x'])) | |
| 232 | $this->send('<x i="'.$this->packet['gp']['x'].'" u="'.$this->userID.'" t="j" />'); //Handle groups
| |
| 233 | break; | |
| 234 | case 'q'://XAT notice to change ip/port | |
| 235 | $this->connect($this->packet['q']['d'], $this->packet['q']['p']); | |
| 236 | $this->join($this->roomID); | |
| 237 | break; | |
| 238 | case 'o': | |
| 239 | $this->packet['o']['u'] = $this->parseU(@$this->packet['u']['u']); | |
| 240 | $this->userInfo[$this->packet['o']['u']]['name'] = @$this->packet['o']['n']; | |
| 241 | $this->userInfo[$this->packet['o']['u']]['registeredName'] = ((isset($this->packet['o']['N']))?$this->packet['o']['N']:''); | |
| 242 | $this->userInfo[$this->packet['o']['u']]['avatar'] = @$this->packet['o']['a']; | |
| 243 | $this->userInfo[$this->packet['o']['u']]['homepage'] = @$this->packet['o']['h']; | |
| 244 | $this->userInfo[$this->packet['o']['u']]['rank'] = $this->f2rank(@$this->packet['o']['f']); | |
| 245 | break; | |
| 246 | case 'u': | |
| 247 | //Joined | |
| 248 | //Default Bot stuff regarding userInformation | |
| 249 | $this->packet['u']['u'] = $this->parseU(@$this->packet['u']['u']); | |
| 250 | $this->userInfo[$this->packet['u']['u']]['name'] = @$this->packet['u']['n']; | |
| 251 | $this->userInfo[$this->packet['u']['u']]['registeredName'] = ((isset($this->packet['u']['N']))?$this->packet['u']['N']:''); | |
| 252 | $this->userInfo[$this->packet['u']['u']]['avatar'] = @$this->packet['u']['a']; | |
| 253 | $this->userInfo[$this->packet['u']['u']]['homepage'] = @$this->packet['u']['h']; | |
| 254 | $this->userInfo[$this->packet['u']['u']]['rank'] = $this->f2rank(@$this->packet['u']['f']); | |
| 255 | ||
| 256 | $event = 'userJoined'; | |
| 257 | $data['id'] = $this->packet['u']['u']; | |
| 258 | $data['old'] = ($type=='o'||(isset($this->packet['u']['s']))?true:false); | |
| 259 | $this->handleEvent($event,$data); | |
| 260 | ||
| 261 | break; | |
| 262 | case 'l': | |
| 263 | //User Left or was kicked, banned | |
| 264 | unset($this->userInfo[$this->packet['l']['u']]); | |
| 265 | $event = 'userLeft'; | |
| 266 | $data['id'] = $this->packet['l']['u']; | |
| 267 | $this->handleEvent($event,$data); | |
| 268 | ||
| 269 | break; | |
| 270 | case 'p': | |
| 271 | //Private message/chat recieved | |
| 272 | $event = ((isset($this->packet['p']['d']))?'privateChat':'privateMessage'); | |
| 273 | $data['id'] = $this->parseU(@$this->packet['p']['u']); | |
| 274 | $data['message'] = $this->packet['p']['t']; | |
| 275 | $this->handleEvent($event,$data); | |
| 276 | break; | |
| 277 | case 'm': | |
| 278 | //message to main chat. | |
| 279 | $event = 'message'; | |
| 280 | $data['id'] = $this->parseU(@$this->packet['m']['u']); | |
| 281 | $data['message'] = $this->packet['m']['t']; | |
| 282 | $data['old'] = ((isset($this->packet['m']['s']))?true:false); | |
| 283 | $this->handleEvent($event,$data); | |
| 284 | break; | |
| 285 | } | |
| 286 | } | |
| 287 | ||
| 288 | /** | |
| 289 | * Joins a room. | |
| 290 | * @param $roomID the numeric roomID to join. | |
| 291 | */ | |
| 292 | function join($roomID) {
| |
| 293 | //Announce we are here: | |
| 294 | $this->send('<y m="1" />');//Anounces our arrival to the server and gets some information to send back
| |
| 295 | $this->read(); //Auto parsed into $this->packet['y'] | |
| 296 | $this->send('<j2 q="1" y="'.$this->packet['y']['i'].'" k="'.$this->k.'" k3="0" z="12" p="0" c="'.$roomID.'" f="0" u="'.$this->userID.'" d0="0" n="'.$this->name.'" a="'.$this->avatar.'" h="'.$this->homepage.'" v="0" />');
| |
| 297 | $this->roomID = $roomID; | |
| 298 | } | |
| 299 | ||
| 300 | /** | |
| 301 | * Parses the u value from a packet to get just the id | |
| 302 | * @param $id the id to be parsed. | |
| 303 | */ | |
| 304 | function parseU($id) {
| |
| 305 | if(substr_count($id,'_')>=1) $id = substr($id,0,strpos($id,'_')); | |
| 306 | return $id; | |
| 307 | } | |
| 308 | ||
| 309 | /** | |
| 310 | * Converts an f value to a string containing the corresponding rank...this if you don't understand bitwise operations is a little 'magical' deal with it. | |
| 311 | * @param $f The f value to be parsed. | |
| 312 | */ | |
| 313 | function f2rank($f) {
| |
| 314 | $f = $this->parseU($f); | |
| 315 | ||
| 316 | if($f==-1) return 'guest'; | |
| 317 | //Okay, 98% of you reading this on NewHax won't know what any of this means; if you do you are more adnvanced than I expected | |
| 318 | //Not that this is advnaced stuff, but basiclly it is a bit-wise comparision(notice & instead of && it is checking if certain binary bits are set to 1 | |
| 319 | //The F value is essientially a bunch of flags where for example 00010000 == banned(the 0s can be 0 or 1, just as long as that one 1 is a one you are banned. | |
| 320 | if((16 & $f)) return 'banned'; | |
| 321 | if((1 & $f)&&(2 & $f)) return 'member'; | |
| 322 | if((4 & $f)) return 'owner'; | |
| 323 | if((32 & $f)&&(1 & $f)&&!(2 & $f)) return 'main'; | |
| 324 | if(!(1 & $f)&&!(2 & $f)) return 'guest'; | |
| 325 | if((16 & $f)) return 'banned'; | |
| 326 | if((2 & $f)&&!(1 & $f)) return 'mod'; | |
| 327 | } | |
| 328 | ||
| 329 | /** | |
| 330 | * Returns an assoc array of information regarding the user with the given id | |
| 331 | * @param $id The user id you want information on. | |
| 332 | */ | |
| 333 | function getUserArray($id) {
| |
| 334 | $id = $this->parseU($id); | |
| 335 | if(isset($this->userInfo[$id])) {
| |
| 336 | return $this->userInfo[$id]; | |
| 337 | } else return false; | |
| 338 | } | |
| 339 | ||
| 340 | /** | |
| 341 | * Sends the given message to the main chat | |
| 342 | * @param $message | |
| 343 | */ | |
| 344 | function sendMessage($message) {
| |
| 345 | if(empty($message))return; | |
| 346 | $this->send('<m t="'.$message.'" u="'.$this->userID.'" />');
| |
| 347 | } | |
| 348 | ||
| 349 | /** | |
| 350 | * Sends a PC to the given ID | |
| 351 | * @param $message The message to send. | |
| 352 | * @param $id The id to send the message to | |
| 353 | */ | |
| 354 | function sendPrivateChat($message, $id) {
| |
| 355 | if(empty($message))return; | |
| 356 | $this->send('<p u="'.$id.'" t="'.$message.'" s="2" d="'.$this->userID.'" />');
| |
| 357 | } | |
| 358 | ||
| 359 | /** | |
| 360 | * Sends a PM to the given ID | |
| 361 | * @param $message The message to send. | |
| 362 | * @param $id The id to send the message to | |
| 363 | */ | |
| 364 | function sendPrivateMessage($message,$id) {
| |
| 365 | $id = $this->parseU($id); | |
| 366 | if(empty($message))return; | |
| 367 | $this->send('<p u="'.$id.'" t="'.$message.'" />');
| |
| 368 | } | |
| 369 | ||
| 370 | /** | |
| 371 | * Makes the given $id an owner, assuming the bot is main | |
| 372 | * @param $id The id to promote | |
| 373 | */ | |
| 374 | function mod($id) {
| |
| 375 | $this->send('<c u="'.$this->parseU($id).'" t="/M" />');
| |
| 376 | } | |
| 377 | ||
| 378 | /** | |
| 379 | * Makes the given $id a mod, assuming the bot is owner | |
| 380 | * @param $id The id to promote | |
| 381 | */ | |
| 382 | function owner($id) {
| |
| 383 | $this->send('<c u="'.$this->parseU($id).'" t="/m" />');
| |
| 384 | } | |
| 385 | ||
| 386 | /** | |
| 387 | * Makes the given $id a member, assuming the bot is mod | |
| 388 | * @param $id The id to member | |
| 389 | */ | |
| 390 | function member($id) {
| |
| 391 | $this->send('<c u="'.$this->parseU($id).'" t="/e" />');
| |
| 392 | } | |
| 393 | ||
| 394 | /** | |
| 395 | * KIcks the given ID assuming the bot is a mod and $id is a member or less | |
| 396 | * @param $id The id to kick | |
| 397 | */ | |
| 398 | function kick($message, $id) {
| |
| 399 | $this->send('<c p="'.$message.'" u="'.$this->parseU($id).'" t="/k" />');
| |
| 400 | } | |
| 401 | ||
| 402 | /** | |
| 403 | * Bans the ID for a given time(0 is forever) | |
| 404 | * @param $id The id to ban | |
| 405 | */ | |
| 406 | function ban($message, $id, $time) {
| |
| 407 | if(empty($time)) $time = 3600; | |
| 408 | $this->send('<c p="'.$message.'" u="'.$this->parseU($id).'" t="/g'.$time.'" />');
| |
| 409 | } | |
| 410 | ||
| 411 | /** | |
| 412 | * Unbans the given ID | |
| 413 | * @param $id The id to unban | |
| 414 | */ | |
| 415 | function unban($id) {
| |
| 416 | $this->send('<c u="'.$this->parseU($id).'" t="/u" />');
| |
| 417 | } | |
| 418 | ||
| 419 | /** | |
| 420 | * Performs a basic HTTP GET to the given URL | |
| 421 | * @param $url The url to retrieve, please include http:// and www if necessary | |
| 422 | * @param $includeHeader Tells teh function wether or not to include the server header respond before the main content | |
| 423 | */ | |
| 424 | function get($url, $includeHeader=false) {
| |
| 425 | $urlp = parse_url($url); | |
| 426 | $fp = fsockopen($urlp['host'],80); | |
| 427 | $path = explode('/',$url,4);
| |
| 428 | $path = ((count($path)>=4)?$path[3]:""); | |
| 429 | $req = "GET /$path HTTP/1.1\r\n"; | |
| 430 | $req .= "Host: $urlp[host]\r\n"; | |
| 431 | $req .= "Connection: Close\r\n\r\n"; | |
| 432 | fputs($fp, $req); | |
| 433 | $res = ""; | |
| 434 | while(!feof($fp)) $res .= fgets($fp, 4096); | |
| 435 | fclose($fp); | |
| 436 | if($includeHeader) return $res; | |
| 437 | $res = explode("\r\n\r\n",$res,2);
| |
| 438 | return $res[1]; | |
| 439 | } | |
| 440 | /** | |
| 441 | * A utility function to get all text beween $start and $end | |
| 442 | * @param $content The content from which we are grabbing data | |
| 443 | * @param $start where to start grabbing from | |
| 444 | * @param $end the end of the content to grab | |
| 445 | */ | |
| 446 | function getBetween($content,$start,$end){
| |
| 447 | $r = explode($start, $content); | |
| 448 | if (isset($r[1])){
| |
| 449 | $r = explode($end, $r[1]); | |
| 450 | return $r[0]; | |
| 451 | } | |
| 452 | return ''; | |
| 453 | } | |
| 454 | ||
| 455 | } | |
| 456 | ||
| 457 | ?> |