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