Remove file execution permission.
[living-lab-site.git] / system / 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 5.1.6 or newer
6  *
7  * @package             CodeIgniter
8  * @author              ExpressionEngine Dev Team
9  * @copyright   Copyright (c) 2008 - 2011, 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         public function __construct()
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
271                 if (stristr($this->response, '<error>0</error>') === FALSE)
272                 {
273                         $message = 'An unknown error was encountered';
274
275                         if (preg_match("/<message>(.*?)<\/message>/is", $this->response, $match))
276                         {
277                                 $message = trim($match['1']);
278                         }
279
280                         $this->set_error($message);
281                         return FALSE;
282                 }
283
284                 return TRUE;
285         }
286
287         // --------------------------------------------------------------------
288
289         /**
290          * Extract Trackback URLs
291          *
292          * This function lets multiple trackbacks be sent.
293          * It takes a string of URLs (separated by comma or
294          * space) and puts each URL into an array
295          *
296          * @access      public
297          * @param       string
298          * @return      string
299          */
300         function extract_urls($urls)
301         {
302                 // Remove the pesky white space and replace with a comma.
303                 $urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls);
304
305                 // If they use commas get rid of the doubles.
306                 $urls = str_replace(",,", ",", $urls);
307
308                 // Remove any comma that might be at the end
309                 if (substr($urls, -1) == ",")
310                 {
311                         $urls = substr($urls, 0, -1);
312                 }
313
314                 // Break into an array via commas
315                 $urls = preg_split('/[,]/', $urls);
316
317                 // Removes duplicates
318                 $urls = array_unique($urls);
319
320                 array_walk($urls, array($this, 'validate_url'));
321
322                 return $urls;
323         }
324
325         // --------------------------------------------------------------------
326
327         /**
328          * Validate URL
329          *
330          * Simply adds "http://" if missing
331          *
332          * @access      public
333          * @param       string
334          * @return      string
335          */
336         function validate_url($url)
337         {
338                 $url = trim($url);
339
340                 if (substr($url, 0, 4) != "http")
341                 {
342                         $url = "http://".$url;
343                 }
344         }
345
346         // --------------------------------------------------------------------
347
348         /**
349          * Find the Trackback URL's ID
350          *
351          * @access      public
352          * @param       string
353          * @return      string
354          */
355         function get_id($url)
356         {
357                 $tb_id = "";
358
359                 if (strpos($url, '?') !== FALSE)
360                 {
361                         $tb_array = explode('/', $url);
362                         $tb_end   = $tb_array[count($tb_array)-1];
363
364                         if ( ! is_numeric($tb_end))
365                         {
366                                 $tb_end  = $tb_array[count($tb_array)-2];
367                         }
368
369                         $tb_array = explode('=', $tb_end);
370                         $tb_id  = $tb_array[count($tb_array)-1];
371                 }
372                 else
373                 {
374                         $url = rtrim($url, '/');
375
376                         $tb_array = explode('/', $url);
377                         $tb_id  = $tb_array[count($tb_array)-1];
378
379                         if ( ! is_numeric($tb_id))
380                         {
381                                 $tb_id  = $tb_array[count($tb_array)-2];
382                         }
383                 }
384
385                 if ( ! preg_match ("/^([0-9]+)$/", $tb_id))
386                 {
387                         return FALSE;
388                 }
389                 else
390                 {
391                         return $tb_id;
392                 }
393         }
394
395         // --------------------------------------------------------------------
396
397         /**
398          * Convert Reserved XML characters to Entities
399          *
400          * @access      public
401          * @param       string
402          * @return      string
403          */
404         function convert_xml($str)
405         {
406                 $temp = '__TEMP_AMPERSANDS__';
407
408                 $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);
409                 $str = preg_replace("/&(\w+);/",  "$temp\\1;", $str);
410
411                 $str = str_replace(array("&","<",">","\"", "'", "-"),
412                                                         array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),
413                                                         $str);
414
415                 $str = preg_replace("/$temp(\d+);/","&#\\1;",$str);
416                 $str = preg_replace("/$temp(\w+);/","&\\1;", $str);
417
418                 return $str;
419         }
420
421         // --------------------------------------------------------------------
422
423         /**
424          * Character limiter
425          *
426          * Limits the string based on the character count. Will preserve complete words.
427          *
428          * @access      public
429          * @param       string
430          * @param       integer
431          * @param       string
432          * @return      string
433          */
434         function limit_characters($str, $n = 500, $end_char = '&#8230;')
435         {
436                 if (strlen($str) < $n)
437                 {
438                         return $str;
439                 }
440
441                 $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
442
443                 if (strlen($str) <= $n)
444                 {
445                         return $str;
446                 }
447
448                 $out = "";
449                 foreach (explode(' ', trim($str)) as $val)
450                 {
451                         $out .= $val.' ';
452                         if (strlen($out) >= $n)
453                         {
454                                 return trim($out).$end_char;
455                         }
456                 }
457         }
458
459         // --------------------------------------------------------------------
460
461         /**
462          * High ASCII to Entities
463          *
464          * Converts Hight ascii text and MS Word special chars
465          * to character entities
466          *
467          * @access      public
468          * @param       string
469          * @return      string
470          */
471         function convert_ascii($str)
472         {
473                 $count  = 1;
474                 $out    = '';
475                 $temp   = array();
476
477                 for ($i = 0, $s = strlen($str); $i < $s; $i++)
478                 {
479                         $ordinal = ord($str[$i]);
480
481                         if ($ordinal < 128)
482                         {
483                                 $out .= $str[$i];
484                         }
485                         else
486                         {
487                                 if (count($temp) == 0)
488                                 {
489                                         $count = ($ordinal < 224) ? 2 : 3;
490                                 }
491
492                                 $temp[] = $ordinal;
493
494                                 if (count($temp) == $count)
495                                 {
496                                         $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);
497
498                                         $out .= '&#'.$number.';';
499                                         $count = 1;
500                                         $temp = array();
501                                 }
502                         }
503                 }
504
505                 return $out;
506         }
507
508         // --------------------------------------------------------------------
509
510         /**
511          * Set error message
512          *
513          * @access      public
514          * @param       string
515          * @return      void
516          */
517         function set_error($msg)
518         {
519                 log_message('error', $msg);
520                 $this->error_msg[] = $msg;
521         }
522
523         // --------------------------------------------------------------------
524
525         /**
526          * Show error messages
527          *
528          * @access      public
529          * @param       string
530          * @param       string
531          * @return      string
532          */
533         function display_errors($open = '<p>', $close = '</p>')
534         {
535                 $str = '';
536                 foreach ($this->error_msg as $val)
537                 {
538                         $str .= $open.$val.$close;
539                 }
540
541                 return $str;
542         }
543
544 }
545 // END Trackback Class
546
547 /* End of file Trackback.php */
548 /* Location: ./system/libraries/Trackback.php */