PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/administrator/components/com_zoo/helpers/comment.php

https://bitbucket.org/organicdevelopment/joomla-2.5
PHP | 428 lines | 170 code | 79 blank | 179 comment | 41 complexity | 9cbe557e9a67c67dc0e1bba042bcbed1 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * @package com_zoo
  4. * @author YOOtheme http://www.yootheme.com
  5. * @copyright Copyright (C) YOOtheme GmbH
  6. * @license http://www.gnu.org/licenses/gpl.html GNU/GPL
  7. */
  8. /**
  9. * The comments helper class.
  10. *
  11. * @package Component.Helpers
  12. * @since 2.0
  13. */
  14. class CommentHelper extends AppHelper {
  15. /**
  16. * The cookie prefix
  17. *
  18. * @var string
  19. * @since 2.0
  20. */
  21. const COOKIE_PREFIX = 'zoo-comment_';
  22. /**
  23. * The cookie lifetime
  24. *
  25. * @var int
  26. * @since 2.0
  27. */
  28. const COOKIE_LIFETIME = 15552000; // 6 months
  29. /**
  30. * Active author.
  31. *
  32. * @var CommentAuthor
  33. * @since 2.0
  34. */
  35. protected $_author;
  36. /**
  37. * Render comments and respond form html.
  38. *
  39. * @param AppView $view The view the comments are rendered on
  40. * @param Item $item The item whos comments are rendered
  41. *
  42. * @return string The html output
  43. *
  44. * @since 2.0
  45. */
  46. public function renderComments($view, $item) {
  47. if ($item->getApplication()->isCommentsEnabled()) {
  48. // get application params
  49. $params = $this->app->parameter->create($item->getApplication()->getParams()->get('global.comments.'));
  50. if ($params->get('twitter_enable') && !function_exists('curl_init')) {
  51. $this->app->error->raiseWarning(500, JText::_('To use Twitter, CURL needs to be enabled in your php settings.'));
  52. $params->set('twitter_enable', false);
  53. }
  54. // get active author
  55. $active_author = $this->activeAuthor();
  56. // get comment content from session
  57. $content = $this->app->system->session->get('com_zoo.comment.content');
  58. $params->set('content', $content);
  59. // get comments and build tree
  60. $comments = $item->getCommentTree(Comment::STATE_APPROVED);
  61. // Only on 2.5
  62. $captcha = $this->app->joomla->version->isCompatible('2.5') && ($plugin = $params->get('captcha', false)) ? JCaptcha::getInstance($plugin) : false;
  63. if ($item->isCommentsEnabled() || count($comments)-1) {
  64. // create comments html
  65. return $view->partial('comments', compact('item', 'active_author', 'comments', 'params', 'captcha'));
  66. }
  67. }
  68. return null;
  69. }
  70. /**
  71. * Retrieve currently active author object.
  72. *
  73. * @return CommentAuthor The active author object
  74. *
  75. * @since 2.0
  76. */
  77. public function activeAuthor() {
  78. if (!isset($this->_author)) {
  79. // get login (joomla users always win)
  80. $login = $this->app->request->getString(self::COOKIE_PREFIX.'login', '', 'cookie');
  81. // get active user
  82. $user = $this->app->user->get();
  83. if ($user->id) {
  84. // create author object from user
  85. $this->_author = $this->app->commentauthor->create('joomla', array($user->name, $user->email, '', $user->id));
  86. } else if ($login == 'facebook'
  87. && ($connection = $this->app->facebook->client())
  88. && ($content = $connection->getCurrentUserProfile())
  89. && isset($content->id)
  90. && isset($content->name)) {
  91. // create author object from facebook user id
  92. $this->_author = $this->app->commentauthor->create('facebook', array($content->name, null, null, $content->id));
  93. } else if ($login == 'twitter'
  94. && ($connection = $this->app->twitter->client())
  95. && ($content = $connection->get('account/verify_credentials'))
  96. && isset($content->screen_name)
  97. && isset($content->id)) {
  98. // create author object from twitter user id
  99. $this->_author = $this->app->commentauthor->create('twitter', array($content->screen_name, null, null, $content->id));
  100. } else {
  101. $this->app->twitter->logout();
  102. $this->app->facebook->logout();
  103. // create author object from cookies
  104. $cookie = $this->readCookies();
  105. $this->_author = $this->app->commentauthor->create('', array($cookie['author'], $cookie['email'], $cookie['url']));
  106. }
  107. }
  108. setcookie(self::COOKIE_PREFIX.'login', $this->_author->getUserType(), time() + self::COOKIE_LIFETIME, '/');
  109. return $this->_author;
  110. }
  111. /**
  112. * Retrieve and verify author, email, url from cookie.
  113. *
  114. * @return array values from cookie
  115. *
  116. * @since 2.0
  117. */
  118. public function readCookies() {
  119. // get cookies
  120. $data = array();
  121. foreach (array('hash', 'author', 'email', 'url') as $key) {
  122. $data[$key] = $this->app->request->getString(self::COOKIE_PREFIX.$key, '', 'cookie');
  123. }
  124. // verify hash
  125. if ($this->getCookieHash($data['author'], $data['email'], $data['url']) == $data['hash']) {
  126. return $data;
  127. }
  128. return array('hash' => null, 'author' => null, 'email' => null, 'url' => null);
  129. }
  130. /**
  131. * Render comments and respond form html.
  132. *
  133. * @param string $author The author name
  134. * @param string $email The author email
  135. * @param string $url The author url
  136. *
  137. * @return void
  138. *
  139. * @since 2.0
  140. */
  141. public function saveCookies($author, $email, $url) {
  142. $hash = $this->getCookieHash($author, $email, $url);
  143. // set cookies
  144. foreach (compact('hash', 'author', 'email', 'url') as $key => $value) {
  145. setcookie(self::COOKIE_PREFIX.$key, $value, time() + self::COOKIE_LIFETIME);
  146. }
  147. }
  148. /**
  149. * Retrieve hash of author and email.
  150. *
  151. * @param string $author The author name
  152. * @param string $email The author email
  153. * @param string $url The author url
  154. *
  155. * @return string the cookie hash
  156. *
  157. * @since 2.0
  158. */
  159. public function getCookieHash($author, $email, $url) {
  160. // get secret from config
  161. $secret = $this->app->system->config->getValue('config.secret');
  162. return md5($author.$email.$url.$secret);
  163. }
  164. /**
  165. * Match words against comments content, author, URL, Email or IP.
  166. *
  167. * @param Comment $comment The comment
  168. * @param array $words The words to match against
  169. *
  170. * @return boolean true on match
  171. *
  172. * @since 2.0
  173. */
  174. public function matchWords($comment, $words) {
  175. $vars = array('author', 'email', 'url', 'ip', 'content');
  176. if ($words = explode("\n", $words)) {
  177. foreach ($words as $word) {
  178. if ($word = trim($word)) {
  179. $pattern = '/'.preg_quote($word).'/i';
  180. foreach ($vars as $var) {
  181. if (preg_match($pattern, $comment->$var)) {
  182. return true;
  183. }
  184. }
  185. }
  186. }
  187. }
  188. return false;
  189. }
  190. /**
  191. * Remove html from comment content
  192. *
  193. * @param string $content The content
  194. *
  195. * @return string the filtered content
  196. *
  197. * @since 2.0
  198. */
  199. public function filterContentInput($content) {
  200. // remove all html tags or escape if in [code] tag
  201. $content = preg_replace_callback('/\[code\](.+?)\[\/code\]/is', create_function('$matches', 'return htmlspecialchars($matches[0]);'), $content);
  202. $content = strip_tags($content);
  203. return $content;
  204. }
  205. /**
  206. * Auto linkify urls, emails
  207. *
  208. * @param string $content The content
  209. *
  210. * @return string the filtered content
  211. *
  212. * @since 2.0
  213. */
  214. public function filterContentOutput($content) {
  215. $content = ' '.$content.' ';
  216. $content = preg_replace_callback('/(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:;,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:;,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:;,.]*\)|[A-Z0-9+&@#\/%=~_|$])/ix', array($this->app->comment, 'makeURLClickable'), $content);
  217. $content = preg_replace("/\s([a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]*\@[a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]{2,6})([\s|\.|\,])/i"," <a href=\"mailto:$1\" rel=\"nofollow\">$1</a>$2", $content);
  218. $content = $this->app->string->substr($content, 1);
  219. $content = $this->app->string->substr($content, 0, -1);
  220. return nl2br($content);
  221. }
  222. /**
  223. * Makes the url clickable (only used as callback internally)
  224. *
  225. * @param array $matches The url matches
  226. *
  227. * @return string the wrapped url
  228. *
  229. * @since 2.0
  230. */
  231. protected function makeURLClickable($matches) {
  232. $url = $original_url = $matches[0];
  233. if (empty($url)) {
  234. return $url;
  235. }
  236. // Prepend scheme if URL appears to contain no scheme (unless a relative link starting with / or a php file).
  237. if (strpos($url, ':') === false && substr($url, 0, 1) != '/' && substr($url, 0, 1) != '#' && !preg_match('/^[a-z0-9-]+?\.php/i', $url)) {
  238. $url = 'http://' . $url;
  239. }
  240. return " <a href=\"$url\" rel=\"nofollow\">$original_url</a>";
  241. }
  242. /**
  243. * Check if comment is spam using Akismet.
  244. *
  245. * @param Comment $comment The Comment object
  246. * @param string $api_key The Akismet API key
  247. *
  248. * @return void
  249. *
  250. * @since 2.0
  251. */
  252. public function akismet($comment, $api_key = '') {
  253. // load akismet class
  254. $this->app->loader->register('Akismet', 'libraries:akismet/akismet.php');
  255. // check comment
  256. $akismet = new Akismet(JURI::root(), $api_key);
  257. $akismet->setCommentAuthor($comment->author);
  258. $akismet->setCommentAuthorEmail($comment->email);
  259. $akismet->setCommentAuthorURL($comment->url);
  260. $akismet->setCommentContent($comment->content);
  261. // set state
  262. if ($akismet->isCommentSpam()) {
  263. $comment->state = Comment::STATE_SPAM;
  264. }
  265. }
  266. /**
  267. * Check if comment is spam using Mollom.
  268. *
  269. * @param Comment $comment The Comment object
  270. * @param string $public_key The Mollom public key
  271. * @param string $private_key The Mollom private key
  272. *
  273. * @return void
  274. *
  275. * @since 2.0
  276. */
  277. public function mollom($comment, $public_key = '', $private_key = '') {
  278. // check if curl functions are available
  279. if (!function_exists('curl_init')) return;
  280. // load mollom class
  281. $this->app->loader->register('Mollom', 'libraries:mollom/mollom.php');
  282. // set keys and get servers
  283. Mollom::setPublicKey($public_key);
  284. Mollom::setPrivateKey($private_key);
  285. Mollom::setServerList(Mollom::getServerList());
  286. // check comment
  287. $feedback = Mollom::checkContent(null, null, $comment->content, $comment->author, $comment->url, $comment->email);
  288. // set state
  289. if ($feedback['spam'] != 'ham') {
  290. $comment->state = Comment::STATE_SPAM;
  291. }
  292. }
  293. /**
  294. * Send notification email
  295. *
  296. * @param Comment $comment The Comment object
  297. * @param array $recipients The recipients email addresses (email => name)
  298. * @param string $layout The layout
  299. *
  300. * @return void
  301. *
  302. * @since 2.0
  303. */
  304. public function sendNotificationMail($comment, $recipients, $layout) {
  305. // workaround to make sure JSite is loaded
  306. $this->app->loader->register('JSite', 'root:includes/application.php');
  307. // init vars
  308. $item = $comment->getItem();
  309. $website_name = $this->app->system->application->getCfg('sitename');
  310. $comment_link = JRoute::_($this->app->route->comment($comment, false), true, -1);
  311. $item_link = JRoute::_($this->app->route->item($item, false), true, -1);
  312. $website_link = JRoute::_('index.php', true, -1);
  313. // send email to $recipients
  314. foreach ($recipients as $email => $name) {
  315. if (empty($email) || $email == $comment->getAuthor()->email) {
  316. continue;
  317. }
  318. // build unsubscribe link
  319. $unsubscribe_link = JURI::root().'index.php?'.http_build_query(array(
  320. 'option' => $this->app->component->self->name,
  321. 'controller' => 'comment',
  322. 'task' => 'unsubscribe',
  323. 'item_id' => $item->id,
  324. 'email' => urldecode($email),
  325. 'hash' => $this->app->comment->getCookieHash($email, $item->id, '')
  326. ), '', '&');
  327. $mail = $this->app->mail->create();
  328. $mail->setSubject(JText::_("Topic reply notification")." - ".$item->name);
  329. $mail->setBodyFromTemplate($item->getApplication()->getTemplate()->resource.$layout, compact(
  330. 'item',
  331. 'comment',
  332. 'website_name',
  333. 'email',
  334. 'name',
  335. 'comment_link',
  336. 'item_link',
  337. 'website_link',
  338. 'unsubscribe_link'
  339. ));
  340. $mail->addRecipient($email);
  341. $mail->Send();
  342. }
  343. }
  344. }
  345. /**
  346. * CommentHelperException identifies an Exception in the CommentHelper class
  347. * @see CommentHelper
  348. */
  349. class CommentHelperException extends AppException {}