Take two:
[www-register-wizard.git] / libraries / Trackback.php
1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\r
2 /**\r
3  * CodeIgniter\r
4  *\r
5  * An open source application development framework for PHP 4.3.2 or newer\r
6  *\r
7  * @package             CodeIgniter\r
8  * @author              ExpressionEngine Dev Team\r
9  * @copyright   Copyright (c) 2008, EllisLab, Inc.\r
10  * @license             http://codeigniter.com/user_guide/license.html\r
11  * @link                http://codeigniter.com\r
12  * @since               Version 1.0\r
13  * @filesource\r
14  */\r
15 \r
16 // ------------------------------------------------------------------------\r
17 \r
18 /**\r
19  * Trackback Class\r
20  *\r
21  * Trackback Sending/Receiving Class\r
22  *\r
23  * @package             CodeIgniter\r
24  * @subpackage  Libraries\r
25  * @category    Trackbacks\r
26  * @author              ExpressionEngine Dev Team\r
27  * @link                http://codeigniter.com/user_guide/libraries/trackback.html\r
28  */\r
29 class CI_Trackback {\r
30                 \r
31         var $time_format        = 'local';\r
32         var $charset            = 'UTF-8';\r
33         var $data                       = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => '');\r
34         var $convert_ascii      = TRUE;\r
35         var $response           = '';\r
36         var $error_msg          = array();\r
37 \r
38         /**\r
39          * Constructor\r
40          *\r
41          * @access      public\r
42          */\r
43         function CI_Trackback()\r
44         {\r
45                 log_message('debug', "Trackback Class Initialized");\r
46         }\r
47         \r
48         // --------------------------------------------------------------------\r
49         \r
50         /**\r
51          * Send Trackback\r
52          *\r
53          * @access      public\r
54          * @param       array\r
55          * @return      bool\r
56          */     \r
57         function send($tb_data)\r
58         {               \r
59                 if ( ! is_array($tb_data))\r
60                 {\r
61                         $this->set_error('The send() method must be passed an array');\r
62                         return FALSE;\r
63                 }\r
64                 \r
65                 // Pre-process the Trackback Data\r
66                 foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item)\r
67                 {\r
68                         if ( ! isset($tb_data[$item]))\r
69                         {\r
70                                 $this->set_error('Required item missing: '.$item);\r
71                                 return FALSE;\r
72                         }\r
73                         \r
74                         switch ($item)\r
75                         {\r
76                                 case 'ping_url' : $$item = $this->extract_urls($tb_data[$item]);\r
77                                         break;\r
78                                 case 'excerpt'  : $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));\r
79                                         break;\r
80                                 case 'url'              : $$item = str_replace('&#45;', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));\r
81                                         break;\r
82                                 default                 : $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item])));\r
83                                         break;\r
84                         }\r
85 \r
86                         // Convert High ASCII Characters\r
87                         if ($this->convert_ascii == TRUE)\r
88                         {\r
89                                 if ($item == 'excerpt')\r
90                                 {\r
91                                         $$item = $this->convert_ascii($$item);\r
92                                 }\r
93                                 elseif ($item == 'title')\r
94                                 {\r
95                                         $$item = $this->convert_ascii($$item);\r
96                                 }\r
97                                 elseif($item == 'blog_name')\r
98                                 {\r
99                                         $$item = $this->convert_ascii($$item);\r
100                                 }\r
101                         }\r
102                 }\r
103 \r
104                 // Build the Trackback data string\r
105                 $charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset'];\r
106                 \r
107                 $data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset);\r
108                                 \r
109                 // Send Trackback(s)\r
110                 $return = TRUE;\r
111                 if (count($ping_url) > 0)\r
112                 {\r
113                         foreach ($ping_url as $url)\r
114                         {\r
115                                 if ($this->process($url, $data) == FALSE)\r
116                                 {\r
117                                         $return = FALSE;\r
118                                 }\r
119                         }       \r
120                 }\r
121 \r
122                 return $return;\r
123         }\r
124         \r
125         // --------------------------------------------------------------------\r
126         \r
127         /**\r
128          * Receive Trackback  Data\r
129          *\r
130          * This function simply validates the incoming TB data.\r
131          * It returns false on failure and true on success.\r
132          * If the data is valid it is set to the $this->data array\r
133          * so that it can be inserted into a database.\r
134          *\r
135          * @access      public\r
136          * @return      bool\r
137          */     \r
138         function receive()\r
139         {                                       \r
140                 foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)\r
141                 {\r
142                         if ( ! isset($_POST[$val]) OR $_POST[$val] == '')\r
143                         {\r
144                                 $this->set_error('The following required POST variable is missing: '.$val);\r
145                                 return FALSE;\r
146                         }\r
147                         \r
148                         $this->data['charset'] = ( ! isset($_POST['charset'])) ? 'auto' : strtoupper(trim($_POST['charset']));\r
149         \r
150                         if ($val != 'url' && function_exists('mb_convert_encoding'))\r
151                         {\r
152                                 $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']);\r
153                         }\r
154                         \r
155                         $_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);\r
156                         \r
157                         if ($val == 'excerpt')\r
158                         {\r
159                                 $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);\r
160                         }\r
161                         \r
162                         $this->data[$val] = $_POST[$val];\r
163                 }\r
164 \r
165                 return TRUE;\r
166         }       \r
167         \r
168         // --------------------------------------------------------------------\r
169         \r
170         /**\r
171          * Send Trackback Error Message\r
172          *\r
173          * Allows custom errors to be set.  By default it\r
174          * sends the "incomplete information" error, as that's\r
175          * the most common one.\r
176          *\r
177          * @access      public\r
178          * @param       string\r
179          * @return      void\r
180          */     \r
181         function send_error($message = 'Incomplete Information')\r
182         {\r
183                 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>";\r
184                 exit;\r
185         }\r
186         \r
187         // --------------------------------------------------------------------\r
188         \r
189         /**\r
190          * Send Trackback Success Message\r
191          *\r
192          * This should be called when a trackback has been\r
193          * successfully received and inserted.\r
194          *\r
195          * @access      public\r
196          * @return      void\r
197          */             \r
198         function send_success()\r
199         {\r
200                 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>0</error>\n</response>";\r
201                 exit;\r
202         }\r
203         \r
204         // --------------------------------------------------------------------\r
205         \r
206         /**\r
207          * Fetch a particular item\r
208          *\r
209          * @access      public\r
210          * @param       string\r
211          * @return      string\r
212          */     \r
213         function data($item)\r
214         {\r
215                 return ( ! isset($this->data[$item])) ? '' : $this->data[$item];\r
216         }\r
217 \r
218         // --------------------------------------------------------------------\r
219         \r
220         /**\r
221          * Process Trackback\r
222          *\r
223          * Opens a socket connection and passes the data to\r
224          * the server.  Returns true on success, false on failure\r
225          *\r
226          * @access      public\r
227          * @param       string\r
228          * @param       string\r
229          * @return      bool\r
230          */     \r
231         function process($url, $data)\r
232         {\r
233                 $target = parse_url($url);\r
234         \r
235                 // Open the socket\r
236                 if ( ! $fp = @fsockopen($target['host'], 80))\r
237                 {\r
238                         $this->set_error('Invalid Connection: '.$url);\r
239                         return FALSE;\r
240                 }\r
241 \r
242                 // Build the path\r
243                 $ppath = ( ! isset($target['path'])) ? $url : $target['path'];\r
244                 \r
245                 $path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath;\r
246 \r
247                 // Add the Trackback ID to the data string\r
248                 if ($id = $this->get_id($url))\r
249                 {\r
250                         $data = "tb_id=".$id."&".$data;\r
251                 }\r
252 \r
253                 // Transfer the data\r
254                 fputs ($fp, "POST " . $path . " HTTP/1.0\r\n" );\r
255                 fputs ($fp, "Host: " . $target['host'] . "\r\n" );\r
256                 fputs ($fp, "Content-type: application/x-www-form-urlencoded\r\n" );\r
257                 fputs ($fp, "Content-length: " . strlen($data) . "\r\n" );\r
258                 fputs ($fp, "Connection: close\r\n\r\n" );\r
259                 fputs ($fp, $data);\r
260 \r
261                 // Was it successful?\r
262                 $this->response = "";\r
263                 \r
264                 while( ! feof($fp))\r
265                 {\r
266                         $this->response .= fgets($fp, 128);\r
267                 }\r
268                 @fclose($fp);\r
269                 \r
270                 if ( ! eregi("<error>0</error>", $this->response))\r
271                 {\r
272                         $message = 'An unknown error was encountered';\r
273                         \r
274                         if (preg_match("/<message>(.*?)<\/message>/is", $this->response, $match))\r
275                         {\r
276                                 $message = trim($match['1']);\r
277                         }\r
278                         \r
279                         $this->set_error($message);\r
280                         return FALSE;\r
281                 }\r
282 \r
283                 return TRUE;\r
284         }\r
285         \r
286         // --------------------------------------------------------------------\r
287         \r
288         /**\r
289          * Extract Trackback URLs\r
290          *\r
291          * This function lets multiple trackbacks be sent.\r
292          * It takes a string of URLs (separated by comma or\r
293          * space) and puts each URL into an array\r
294          *\r
295          * @access      public\r
296          * @param       string\r
297          * @return      string\r
298          */     \r
299         function extract_urls($urls)\r
300         {               \r
301                 // Remove the pesky white space and replace with a comma.\r
302                 $urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls);\r
303                 \r
304                 // If they use commas get rid of the doubles.\r
305                 $urls = str_replace(",,", ",", $urls);\r
306                 \r
307                 // Remove any comma that might be at the end\r
308                 if (substr($urls, -1) == ",")\r
309                 {\r
310                         $urls = substr($urls, 0, -1);\r
311                 }\r
312                                 \r
313                 // Break into an array via commas\r
314                 $urls = preg_split('/[,]/', $urls);\r
315                 \r
316                 // Removes duplicates\r
317                 $urls = array_unique($urls);\r
318                 \r
319                 array_walk($urls, array($this, 'validate_url'));\r
320                 \r
321                 return $urls;\r
322         }\r
323         \r
324         // --------------------------------------------------------------------\r
325         \r
326         /**\r
327          * Validate URL\r
328          *\r
329          * Simply adds "http://" if missing\r
330          *\r
331          * @access      public\r
332          * @param       string\r
333          * @return      string\r
334          */     \r
335         function validate_url($url)\r
336         {\r
337                 $url = trim($url);\r
338 \r
339                 if (substr($url, 0, 4) != "http")\r
340                 {\r
341                         $url = "http://".$url;\r
342                 }\r
343         }\r
344         \r
345         // --------------------------------------------------------------------\r
346         \r
347         /**\r
348          * Find the Trackback URL's ID\r
349          *\r
350          * @access      public\r
351          * @param       string\r
352          * @return      string\r
353          */     \r
354         function get_id($url)\r
355         {       \r
356                 $tb_id = "";\r
357                 \r
358                 if (strstr($url, '?'))\r
359                 {\r
360                         $tb_array = explode('/', $url);\r
361                         $tb_end   = $tb_array[count($tb_array)-1];\r
362                         \r
363                         if ( ! is_numeric($tb_end))\r
364                         {\r
365                                 $tb_end  = $tb_array[count($tb_array)-2];\r
366                         }\r
367                         \r
368                         $tb_array = explode('=', $tb_end);\r
369                         $tb_id  = $tb_array[count($tb_array)-1];\r
370                 }\r
371                 else\r
372                 {\r
373                         if (ereg("/$", $url))\r
374                         {\r
375                                 $url = substr($url, 0, -1);\r
376                         }\r
377                                 \r
378                         $tb_array = explode('/', $url);\r
379                         $tb_id  = $tb_array[count($tb_array)-1];\r
380                         \r
381                         if ( ! is_numeric($tb_id))\r
382                         {\r
383                                 $tb_id  = $tb_array[count($tb_array)-2];\r
384                         }\r
385                 }       \r
386                                 \r
387                 if ( ! preg_match ("/^([0-9]+)$/", $tb_id))\r
388                 {\r
389                         return false;\r
390                 }\r
391                 else\r
392                 {\r
393                         return $tb_id;\r
394                 }               \r
395         }\r
396         \r
397         // --------------------------------------------------------------------\r
398         \r
399         /**\r
400          * Convert Reserved XML characters to Entities\r
401          *\r
402          * @access      public\r
403          * @param       string\r
404          * @return      string\r
405          */\r
406         function convert_xml($str)\r
407         {\r
408                 $temp = '__TEMP_AMPERSANDS__';\r
409                 \r
410                 $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);\r
411                 $str = preg_replace("/&(\w+);/",  "$temp\\1;", $str);\r
412                 \r
413                 $str = str_replace(array("&","<",">","\"", "'", "-"),\r
414                                                    array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),\r
415                                                    $str);\r
416                         \r
417                 $str = preg_replace("/$temp(\d+);/","&#\\1;",$str);\r
418                 $str = preg_replace("/$temp(\w+);/","&\\1;", $str);\r
419                         \r
420                 return $str;\r
421         }       \r
422         \r
423         // --------------------------------------------------------------------\r
424         \r
425         /**\r
426          * Character limiter\r
427          *\r
428          * Limits the string based on the character count. Will preserve complete words.\r
429          *\r
430          * @access      public\r
431          * @param       string\r
432          * @param       integer\r
433          * @param       string\r
434          * @return      string\r
435          */\r
436         function limit_characters($str, $n = 500, $end_char = '&#8230;')\r
437         {\r
438                 if (strlen($str) < $n)\r
439                 {\r
440                         return $str;\r
441                 }\r
442 \r
443                 $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));\r
444         \r
445                 if (strlen($str) <= $n)\r
446                 {\r
447                         return $str;\r
448                 }\r
449                                                                                 \r
450                 $out = "";\r
451                 foreach (explode(' ', trim($str)) as $val)\r
452                 {\r
453                         $out .= $val.' ';                       \r
454                         if (strlen($out) >= $n)\r
455                         {\r
456                                 return trim($out).$end_char;\r
457                         }               \r
458                 }\r
459         }\r
460         \r
461         // --------------------------------------------------------------------\r
462         \r
463         /**\r
464          * High ASCII to Entities\r
465          *\r
466          * Converts Hight ascii text and MS Word special chars\r
467          * to character entities\r
468          *\r
469          * @access      public\r
470          * @param       string\r
471          * @return      string\r
472          */\r
473         function convert_ascii($str)\r
474         {\r
475            $count       = 1;\r
476            $out = '';\r
477            $temp        = array();\r
478                 \r
479            for ($i = 0, $s = strlen($str); $i < $s; $i++)\r
480            {\r
481                    $ordinal = ord($str[$i]);\r
482                 \r
483                    if ($ordinal < 128)\r
484                    {\r
485                            $out .= $str[$i];                    \r
486                    }\r
487                    else\r
488                    {\r
489                            if (count($temp) == 0)\r
490                            {\r
491                                    $count = ($ordinal < 224) ? 2 : 3;\r
492                            }\r
493                         \r
494                            $temp[] = $ordinal;\r
495                         \r
496                            if (count($temp) == $count)\r
497                            {\r
498                                    $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);\r
499         \r
500                                    $out .= '&#'.$number.';';\r
501                                    $count = 1;\r
502                                    $temp = array();\r
503                            }\r
504                    }\r
505            }\r
506         \r
507            return $out;\r
508         }\r
509         \r
510         // --------------------------------------------------------------------\r
511         \r
512         /**\r
513          * Set error message\r
514          *\r
515          * @access      public\r
516          * @param       string\r
517          * @return      void\r
518          */     \r
519         function set_error($msg)\r
520         {\r
521                 log_message('error', $msg);\r
522                 $this->error_msg[] = $msg;\r
523         }\r
524         \r
525         // --------------------------------------------------------------------\r
526         \r
527         /**\r
528          * Show error messages\r
529          *\r
530          * @access      public\r
531          * @param       string\r
532          * @param       string\r
533          * @return      string\r
534          */     \r
535         function display_errors($open = '<p>', $close = '</p>')\r
536         {       \r
537                 $str = '';\r
538                 foreach ($this->error_msg as $val)\r
539                 {\r
540                         $str .= $open.$val.$close;\r
541                 }\r
542         \r
543                 return $str;\r
544         }\r
545 \r
546 }\r
547 // END Trackback Class\r
548 \r
549 /* End of file Trackback.php */\r
550 /* Location: ./system/libraries/Trackback.php */