blob: 6d5e206ffb09db4efac49b8bc7d5e212ba3a0df0 [file] [log] [blame]
adminb0dd10f2006-08-25 17:25:49 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
admine334c472006-10-21 19:44:22 +000010 * @license http://www.codeignitor.com/user_guide/license.html
adminb0dd10f2006-08-25 17:25:49 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
admine79dc712006-09-26 03:52:45 +000015
adminb0dd10f2006-08-25 17:25:49 +000016// ------------------------------------------------------------------------
17
18/**
19 * Trackback Class
20 *
21 * Trackback Sending/Receiving Class
admine334c472006-10-21 19:44:22 +000022 *
adminb0dd10f2006-08-25 17:25:49 +000023 * @package CodeIgniter
24 * @subpackage Libraries
25 * @category Trackbacks
26 * @author Paul Burdick
27 * @link http://www.codeigniter.com/user_guide/libraries/trackback.html
28 */
29class 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))
admine334c472006-10-21 19:44:22 +000060 {
adminb0dd10f2006-08-25 17:25:49 +000061 $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]))
admine334c472006-10-21 19:44:22 +000069 {
adminb0dd10f2006-08-25 17:25:49 +000070 $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
admine334c472006-10-21 19:44:22 +0000107 $data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset);
adminb0dd10f2006-08-25 17:25:49 +0000108
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;
adminbd6bee72006-10-21 19:39:00 +0000123 }
adminb0dd10f2006-08-25 17:25:49 +0000124
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 }
adminb0dd10f2006-08-25 17:25:49 +0000167
168 // --------------------------------------------------------------------
169
170 /**
171 * Send Trackback Error Message
172 *
admine334c472006-10-21 19:44:22 +0000173 * Allows custom errors to be set. By default it
adminb0dd10f2006-08-25 17:25:49 +0000174 * 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 }
adminb0dd10f2006-08-25 17:25:49 +0000186
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 }
adminb0dd10f2006-08-25 17:25:49 +0000203
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 }
adminb0dd10f2006-08-25 17:25:49 +0000217
218 // --------------------------------------------------------------------
219
220 /**
221 * Process Trackback
222 *
admine334c472006-10-21 19:44:22 +0000223 * Opens a socket connection and passes the data to
adminb0dd10f2006-08-25 17:25:49 +0000224 * 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 }
admine334c472006-10-21 19:44:22 +0000252
adminb0dd10f2006-08-25 17:25:49 +0000253 // Transfer the data
admine334c472006-10-21 19:44:22 +0000254 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" );
adminb0dd10f2006-08-25 17:25:49 +0000259 fputs ($fp, $data);
admine334c472006-10-21 19:44:22 +0000260
adminb0dd10f2006-08-25 17:25:49 +0000261 // Was it successful?
262 $this->response = "";
263
264 while(!feof($fp))
265 {
266 $this->response .= fgets($fp, 128);
admine334c472006-10-21 19:44:22 +0000267 }
adminb0dd10f2006-08-25 17:25:49 +0000268 @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 }
adminb0dd10f2006-08-25 17:25:49 +0000285
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)
admine334c472006-10-21 19:44:22 +0000300 {
adminb0dd10f2006-08-25 17:25:49 +0000301 // 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
admine334c472006-10-21 19:44:22 +0000319 array_walk($urls, array($this, 'validate_url'));
adminb0dd10f2006-08-25 17:25:49 +0000320
321 return $urls;
322 }
adminb0dd10f2006-08-25 17:25:49 +0000323
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 }
adminb0dd10f2006-08-25 17:25:49 +0000344
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
admin1cf89aa2006-09-03 18:24:39 +0000363 if ( ! is_numeric($tb_end))
adminb0dd10f2006-08-25 17:25:49 +0000364 {
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
admin1cf89aa2006-09-03 18:24:39 +0000381 if ( ! is_numeric($tb_id))
adminb0dd10f2006-08-25 17:25:49 +0000382 {
383 $tb_id = $tb_array[count($tb_array)-2];
384 }
385 }
386
admine334c472006-10-21 19:44:22 +0000387 if ( ! preg_match ("/^([0-9]+)$/", $tb_id))
adminb0dd10f2006-08-25 17:25:49 +0000388 {
389 return false;
390 }
391 else
392 {
393 return $tb_id;
394 }
395 }
adminb0dd10f2006-08-25 17:25:49 +0000396
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 }
adminb0dd10f2006-08-25 17:25:49 +0000422
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 {
admine334c472006-10-21 19:44:22 +0000438 if (strlen($str) < $n)
adminb0dd10f2006-08-25 17:25:49 +0000439 {
440 return $str;
441 }
442
443 $str = preg_replace("/\s+/", ' ', preg_replace("/(\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 {
admine334c472006-10-21 19:44:22 +0000456 return trim($out).$end_char;
adminb0dd10f2006-08-25 17:25:49 +0000457 }
458 }
459 }
adminb0dd10f2006-08-25 17:25:49 +0000460
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();
admine334c472006-10-21 19:44:22 +0000478
adminb0dd10f2006-08-25 17:25:49 +0000479 for ($i = 0, $s = strlen($str); $i < $s; $i++)
480 {
481 $ordinal = ord($str[$i]);
admine334c472006-10-21 19:44:22 +0000482
adminb0dd10f2006-08-25 17:25:49 +0000483 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 }
admine334c472006-10-21 19:44:22 +0000493
adminb0dd10f2006-08-25 17:25:49 +0000494 $temp[] = $ordinal;
admine334c472006-10-21 19:44:22 +0000495
adminb0dd10f2006-08-25 17:25:49 +0000496 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();
admine334c472006-10-21 19:44:22 +0000503 }
504 }
adminb0dd10f2006-08-25 17:25:49 +0000505 }
admine334c472006-10-21 19:44:22 +0000506
adminb0dd10f2006-08-25 17:25:49 +0000507 return $out;
508 }
adminb0dd10f2006-08-25 17:25:49 +0000509
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 }
adminb0dd10f2006-08-25 17:25:49 +0000524
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 }
adminbd6bee72006-10-21 19:39:00 +0000545
adminb0dd10f2006-08-25 17:25:49 +0000546}
547// END Trackback Class
548?>