PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/many_one/system/libraries/Trackback.php

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