ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilLinkChecker.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
13 {
14  var $db = null;
15  var $log_messages = array();
16  var $invalid_links = array();
17 
18  var $validate_all = true;
19  var $mail_status = false;
20  var $page_id = 0;
21 
22 
23  function ilLinkChecker(&$db,$a_validate_all = true)
24  {
25  global $ilDB;
26 
27  define('DEBUG',1);
28  define('SOCKET_TIMEOUT',5);
29 
30  $this->db =& $db;
31 
32  // SET GLOBAL DB HANDLER FOR STATIC METHODS OTHER CLASSES
33  $ilDB =& $db;
34 
35  $this->validate_all = $a_validate_all;
36  }
37 
38  function setCheckPeriod($a_period)
39  {
40  $this->period = $a_period;
41  }
42  function getCheckPeriod()
43  {
44  return $this->period;
45  }
46 
47  function setMailStatus($a_status)
48  {
49  $this->mail_status = (bool) $a_status;
50  }
51  function getMailStatus()
52  {
53  return (bool) $this->mail_status;
54  }
55 
56  function __setType($a_type)
57  {
58  $this->type = $a_type;
59  }
60  function __getType()
61  {
62  return $this->type;
63  }
64 
65  function setObjId($a_page_id)
66  {
67  return $this->page_id = $a_page_id;
68  }
69  function getObjId()
70  {
71  return $this->page_id;
72  }
73 
74  function getValidateAll()
75  {
76  return $this->validate_all ? true : false;
77  }
78 
79  function getLogMessages()
80  {
81  return $this->log_messages ? $this->log_messages : array();
82  }
83 
84  function getInvalidLinks()
85  {
86  return $this->invalid_links ? $this->invalid_links : array();
87  }
88 
90  {
91  global $ilDB;
92 
93  $query = "SELECT * FROM link_check ".
94  "WHERE obj_id = ".$ilDB->quote($this->getObjId(),'integer')." ";
95 
96  $res = $this->db->query($query);
97  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
98  {
99  $invalid[] = array('page_id' => $row->page_id,
100  'url' => $row->url);
101  }
102 
103  return $invalid ? $invalid : array();
104  }
105 
107  {
108  global $ilDB;
109 
110  if($this->getValidateAll())
111  {
112  $query = "SELECT MAX(last_check) last_check FROM link_check ";
113  }
114  else
115  {
116  $query = "SELECT MAX(last_check) last_check FROM link_check ".
117  "WHERE obj_id = ".$ilDB->quote($this->getObjId(),'integer')." ";
118  }
119  $res = $ilDB->query($query);
120  $row = $ilDB->fetchObject($res);
121 
122  return $row->last_check ? $row->last_check : 0;
123  }
124 
126  {
127  $pages = array();
128 
129  $this->__setType('webr');
130  $this->__clearLogMessages();
131  $this->__clearInvalidLinks();
132  $this->__appendLogMessage('LinkChecker: Start checkLinks()');
133 
134  if(count($invalid = $this->__validateLinks($this->__getWebResourceLinks())))
135  {
136  foreach($invalid as $invalid_item)
137  {
138  $this->__appendLogMessage('LinkChecker: found invalid link: '.$invalid_item['complete']);
139  $this->__appendInvalidLink($invalid_item);
140  }
141  }
142 
143  $this->__appendLogMessage('LinkChecker: End checkLinks()');
144  $this->__saveInDB();
145 
146  $this->__sendMail();
147 
148  return $this->getInvalidLinks();
149  }
150 
151  function checkLinks()
152  {
153  global $ilDB;
154 
155  $pages = array();
156 
157  $this->__setType('lm');
158  $this->__clearLogMessages();
159  $this->__clearInvalidLinks();
160  $this->__appendLogMessage('LinkChecker: Start checkLinks()');
161 
162  if(!$this->getValidateAll() and !$this->getObjId())
163  {
164  echo "ilLinkChecker::checkLinks() No Page id given";
165 
166  return false;
167  }
168  elseif(!$this->getValidateAll() and $this->getObjId())
169  {
170  $query = "SELECT * FROM page_object ".
171  "WHERE parent_id = ".$ilDB->quote($this->getObjId())." ".
172  "AND parent_type = 'lm'";
173 
174  $res = $this->db->query($query);
175  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
176  {
177  $pages[] = array('page_id' => $row->page_id,
178  'content' => $row->content,
179  'type' => $row->parent_type);
180  }
181  }
182  elseif($this->getValidateAll())
183  {
184  $query = "SELECT * FROM page_object ".
185  "WHERE parent_type = 'lm'";
186 
187  $res = $this->db->query($query);
188  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
189  {
190  $pages[] = array('page_id' => $row->page_id,
191  'content' => $row->content,
192  'type' => $row->parent_type);
193  }
194  }
195 
196  // VALIDATE
197  foreach($pages as $page)
198  {
199  if(count($invalid = $this->__validateLinks($this->__getLinks($page))))
200  {
201  foreach($invalid as $invalid_item)
202  {
203  $this->__appendLogMessage('LinkChecker: found invalid link: '.$invalid_item['complete']);
204  $this->__appendInvalidLink($invalid_item);
205  }
206  }
207  }
208 
209  $this->__appendLogMessage('LinkChecker: End checkLinks()');
210  $this->__saveInDB();
211 
212  $this->__sendMail();
213 
214  return $this->getInvalidLinks();
215  }
216 
217  function checkPear()
218  {
219  if(!@include_once('HTTP/Request.php'))
220  {
221  return false;
222  }
223  return true;
224  }
225 
226 
227  // PRIVATE
228  function __txt($language,$key,$module = 'common')
229  {
230  global $ilDB;
231 
232  include_once './Services/Language/classes/class.ilLanguage.php';
233  return ilLanguage::_lookupEntry($language, $module, $key);
234  }
235 
236  function __fetchUserData($a_usr_id)
237  {
238  global $ilDB;
239 
240  $query = "SELECT email FROM usr_data WHERE usr_id = ".$ilDB->quote($a_usr_id)."";
241 
242  $row = $this->db->getRow($query,DB_FETCHMODE_OBJECT);
243 
244  $data['email'] = $row->email;
245 
246  $set = $ilDB->query("SELECT * FROM usr_pref ".
247  "WHERE usr_id = ".$ilDB->quote($a_usr_id, "integer")." ".
248  "AND keyword = ".$ilDB->quote('language', "text"));
249 
250  $row = $ilDB->fetchObject($set);
251 
252  $data['lang'] = $row->value;
253 
254  return $data;
255  }
256 
257  function __getTitle($a_lm_obj_id)
258  {
259  global $ilDB;
260 
261  $query = "SELECT title FROM object_data ".
262  "WHERE obj_id = ".$ilDB->quote($a_lm_obj_id ,'integer')." ";
263 
264  $row = $this->db->getRow($query,DB_FETCHMODE_OBJECT);
265 
266  return $row->title;
267  }
268 
269  function __sendMail()
270  {
271  global $ilUser;
272 
273 
274  if(!count($notify = $this->__getNotifyLinks()))
275  {
276  // Nothing to do
277  return true;
278  }
279  if(!$this->getMailStatus())
280  {
281  return true;
282  }
283 
284  include_once './Services/LinkChecker/classes/class.ilLinkCheckNotify.php';
285  $body = "";
286  $obj_name = "";
287 
288  foreach(ilLinkCheckNotify::_getAllNotifiers($this->db) as $usr_id => $obj_ids)
289  {
290  if(!is_object($tmp_user =& ilObjectFactory::getInstanceByObjId($usr_id,false)))
291  {
292  $this->__appendLogMessage('LinkChecker: Cannot find user with id: '.$usr_id);
293  continue;
294  }
295 
296  $counter = 0;
297  foreach($obj_ids as $obj_id)
298  {
299  if(!isset($notify[$obj_id]))
300  {
301  continue;
302  }
303  ++$counter;
304 
305  switch($this->__getType())
306  {
307  case 'webr':
308  $obj_name = $this->__txt($tmp_user->getLanguage(),'obj_webr');
309  break;
310  case 'lm':
311  default:
312  $obj_name = $this->__txt($tmp_user->getLanguage(),'lo');
313  break;
314  }
315  $body .= $obj_name.': '.$this->__getTitle($obj_id)."\r\n";
316  $body .= $this->__txt($tmp_user->getLanguage(),'link_check_perma_link', "mail"). ": " .
317  $this->createPermanentLink($obj_id, $usr_id, $this->__getType())." \r\n";
318  $body .= $this->__txt($tmp_user->getLanguage(),"link_check_affected_links", "mail"). ":\r\n";
319 
320  // Print all invalid
321  foreach($notify[$obj_id] as $data)
322  {
323  $body .= $data['url']."\r\n";
324  }
325  $body .= "\r\n";
326  }
327  if($counter)
328  {
329  include_once "./Services/Notification/classes/class.ilSystemNotification.php";
330  $ntf = new ilSystemNotification();
331  $ntf->setLangModules(array("mail", "common"));
332  $ntf->setSubjectLangId("link_check_subject");
333  $ntf->setIntroductionLangId("link_check_introduction");
334  $ntf->setReasonLangId("link_check_reason");
335  $ntf->addAdditionalInfo("additional_info", $body,true);
336  $ntf->sendMail(array($tmp_user->getId()));
337 
338  $this->__appendLogMessage('LinkChecker: Sent mail to '.$tmp_user->getEmail());
339  }
340  $body = "";
341  }
342  }
343 
351  protected function createPermanentLink($a_obj_id, $a_usr_id, $a_obj_type)
352  {
353  global $ilAccess;
354  $ref_ids = ilObject::_getAllReferences($a_obj_id);
355  $ref_id = null;
356 
357  foreach((array) $ref_ids as $id)
358  {
359  if($ilAccess->checkAccessOfUser($a_usr_id, "read", "", $id, $a_obj_type, $a_obj_id))
360  {
361  $ref_id = $id;
362  }
363  }
364 
365  if($ref_id === null)
366  {
367  return false;
368  }
369 
370  include_once './Services/Link/classes/class.ilLink.php';
371  return ilLink::_getLink($ref_id, $a_obj_type);
372  }
373 
374  function __getNotifyLinks()
375  {
376  return $this->notify ? $this->notify : array();
377  }
378 
379 
381  {
382  $this->invalid_links = array();
383  }
384  function __appendInvalidLink($a_link)
385  {
386  $this->invalid_links[] = $a_link;
387  }
388 
389 
390  function __appendLogMessage($a_string)
391  {
392  $this->log_messages[] = $a_string;
393  }
395  {
396  return $this->log_messages = array();
397  }
398 
399  function __getLinks($a_page)
400  {
401  $matches = array();
402 
403  $pattern_complete = '/<ExtLink Href="([^"]*)">/';
404  if(preg_match_all($pattern_complete,$a_page['content'],$matches))
405  {
406  for($i = 0;$i < count($matches[0]); ++$i)
407  {
408  $url_data = @parse_url($matches[1][$i]);
409  // continue if mailto link
410  if($url_data['scheme'] == 'mailto')
411  {
412  continue;
413  }
414 
415  // PUH, HTTP_REQUEST needs a beginning http://
416  if(!$url_data['scheme'])
417  {
418  $matches[1][$i] = 'http://'.$matches[1][$i];
419  }
420 
421  $lm_id = $this->__getObjIdByPageId($a_page['page_id']);
422  $link[] = array('page_id' => $a_page['page_id'],
423  'obj_id' => $lm_id,
424  'type' => $a_page['type'],
425  'complete' => $matches[1][$i],
426  'scheme' => isset($url_data['scheme']) ? $url_data['scheme'] : 'http',
427  'host' => isset($url_data['host']) ? $url_data['host'] : $url_data['path']);
428  }
429  }
430 
431  return $link ? $link : array();
432  }
433 
435  {
436  global $objDefinition;
437 
438  include_once 'Modules/WebResource/classes/class.ilLinkResourceItems.php';
439 
440  $link_res_obj = new ilLinkResourceItems($this->getObjId());
441 
442  foreach($check_links = $link_res_obj->getCheckItems($this->getCheckPeriod()) as $item_data)
443  {
444  // #10091 - internal
445  if(strpos($item_data['target'], '|'))
446  {
447  $parts = explode('|', $item_data['target']);
448  if(sizeof($parts) == 2 &&
449  is_numeric($parts[1]) &&
450  $objDefinition->isAllowedInRepository($parts[0]))
451  {
452  $link[] = array('page_id' => $item_data['link_id'],
453  'obj_id' => $this->getObjId(),
454  'type' => 'webr',
455  'complete' => $item_data['target'],
456  'scheme' => 'internal',
457  'obj_type' => $parts[0],
458  'ref_id' => $parts[1]);
459  continue;
460  }
461  }
462 
463  // external
464  $url_data = @parse_url($item_data['target']);
465 
466  // PUH, HTTP_REQUEST needs a beginning http://
467  if(!$url_data['scheme'])
468  {
469  $item_data['target'] = 'http://'.$item_data['target'];
470  }
471 
472  $link[] = array('page_id' => $item_data['link_id'],
473  'obj_id' => $this->getObjId(),
474  'type' => 'webr',
475  'complete' => $item_data['target'],
476  'scheme' => isset($url_data['scheme']) ? $url_data['scheme'] : 'http',
477  'host' => isset($url_data['host']) ? $url_data['host'] : $url_data['path']);
478  }
479  return $link ? $link : array();
480  }
481 
482 
483 
484  function __validateLinks($a_links)
485  {
486  global $tree;
487 
488  if(!@include_once('HTTP/Request.php'))
489  {
490  $this->__appendLogMessage('LinkChecker: Pear HTTP_Request is not installed. Aborting');
491 
492  return array();
493  }
494 
495  foreach($a_links as $link)
496  {
497  // #10091 - internal
498  if($link['scheme'] == 'internal')
499  {
500  $obj_id = ilObject::_lookupObjId($link['ref_id']);
501  if(!$obj_id ||
502  ilObject::_lookupType($obj_id) != $link['obj_type'] ||
503  $tree->isDeleted($link['ref_id']))
504  {
505  $invalid[] = $link;
506  }
507  }
508  // external
509  else
510  {
511  if(gethostbyname($link['host']) == $link['host'])
512  {
513  $invalid[] = $link;
514  continue;
515  }
516 
517  if($link['scheme'] !== 'http' and $link['scheme'] !== 'https')
518  {
519  continue;
520  }
521 
522  require_once './Services/Http/classes/class.ilProxySettings.php';
523 
524  if(ilProxySettings::_getInstance()->isActive())
525  {
526  $options = array('proxy_host' => ilProxySettings::_getInstance()->getHost(),
527  'proxy_port' => ilProxySettings::_getInstance()->getPort());
528  }
529  else
530  {
531  $options = array();
532  }
533 
534  $req = new HTTP_Request($link['complete'], $options);
535  $req->sendRequest();
536 
537  switch($req->getResponseCode())
538  {
539  // EVERYTHING OK
540  case '200':
541  // In the moment 301 will be handled as ok
542  case '301':
543  case '302':
544  break;
545 
546  default:
547  $link['http_status_code'] = $req->getResponseCode();
548  $invalid[] = $link;
549  break;
550  }
551  }
552  }
553  return $invalid ? $invalid : array();
554  }
555 
556  function __getObjIdByPageId($a_page_id)
557  {
558  $query = "SELECT lm_id FROM lm_data ".
559  "WHERE obj_id = '".$a_page_id."'";
560 
561  $row = $this->db->getRow($query,DB_FETCHMODE_OBJECT);
562 
563  return $row->lm_id ? $row->lm_id : 0;
564  }
565 
566  function __isInvalid($a_page_id, $a_url)
567  {
568  foreach($this->getInvalidLinks() as $link)
569  {
570  if($link['page_id'] == $a_page_id and
571  substr($link['complete'],0,255) == $a_url)
572  {
573  return true;
574  }
575  }
576  return false;
577  }
578 
579  function __saveInDB()
580  {
581  global $ilDB;
582 
583  if($this->getMailStatus())
584  {
585  $this->__checkNotify();
586  }
587  $this->__clearDBData();
588 
589 
590  foreach($this->getInvalidLinks() as $link)
591  {
592  $query = "INSERT INTO link_check (obj_id,page_id,url,parent_type,http_status_code,last_check) ".
593  "VALUES ( ".
594  $ilDB->quote($link['obj_id'],'integer').", ".
595  $ilDB->quote($link['page_id'],'integer').", ".
596  $ilDB->quote(substr($link['complete'],0,255),'text').", ".
597  $ilDB->quote($link['type'],'text').", ".
598  $ilDB->quote($link['http_status_code'] ? $link['http_status_code'] : 0,'integer').", ".
599  $ilDB->quote(time(),'integer')." ".
600  ")";
601  $res = $ilDB->manipulate($query);
602  }
603  }
604 
605  function __checkNotify()
606  {
607  global $ilDB;
608 
609  foreach($this->getInvalidLinks() as $link)
610  {
611  $query = "SELECT * FROM link_check ".
612  "WHERE page_id = ".$ilDB->quote($link['page_id'],'integer')." ".
613  "AND url = ".$ilDB->quote(substr($link['complete'],0,255),'text')." ";
614  $res = $ilDB->query($query);
615 
616  if(!$res->numRows())
617  {
618  $this->notify[$link["obj_id"]][] = array('page_id' => $link['page_id'],
619  'url' => $link['complete']);
620  }
621  }
622  }
623 
624 
625  function __clearDBData()
626  {
627  global $ilDB;
628 
629  if($this->getValidateAll())
630  {
631  $query = "DELETE FROM link_check";
632  }
633  else
634  {
635  $query = "DELETE FROM link_check ".
636  "WHERE obj_id = ".$ilDB->quote($this->getObjId(),'integer');
637  }
638  $res = $ilDB->manipulate($query);
639 
640  return true;
641  }
642 }
643 ?>