ILIAS  release_4-3 Revision
 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 
286  foreach(ilLinkCheckNotify::_getAllNotifiers($this->db) as $usr_id => $obj_ids)
287  {
288  if(!is_object($tmp_user =& ilObjectFactory::getInstanceByObjId($usr_id,false)))
289  {
290  $this->__appendLogMessage('LinkChecker: Cannot find user with id: '.$usr_id);
291  continue;
292  }
293 
294  $counter = 0;
295  foreach($obj_ids as $obj_id)
296  {
297  if(!isset($notify[$obj_id]))
298  {
299  continue;
300  }
301  ++$counter;
302 
303  switch($this->__getType())
304  {
305  case 'webr':
306  $body .= $this->__txt($tmp_user->getLanguage(),'obj_webr');
307  break;
308 
309  case 'lm':
310  default:
311  $body .= $this->__txt($tmp_user->getLanguage(),'lo');
312  break;
313  }
314 
315  $body .= ': ';
316  $body .= $this->__getTitle($obj_id)."\r\n";
317 
318  // Print all invalid
319  foreach($notify[$obj_id] as $data)
320  {
321  $body .= $data['url']."\r\n";
322  }
323  $body .= "\r\n";
324  }
325  if($counter)
326  {
327  include_once "Services/Mail/classes/class.ilFormatMail.php";
328 
329  $umail = new ilFormatMail($tmp_user->getId());
330  $subject = $this->__txt($tmp_user->getLanguage(),'link_check_subject');
331 
332  $umail->sendMail($tmp_user->getLogin(),"","",$subject,$body,array(),array("normal"));
333  $this->__appendLogMessage('LinkChecker: Sent mail to '.$tmp_user->getEmail());
334  }
335 
336  }
337 
338 
339  }
340 
341  function __getNotifyLinks()
342  {
343  return $this->notify ? $this->notify : array();
344  }
345 
346 
348  {
349  $this->invalid_links = array();
350  }
351  function __appendInvalidLink($a_link)
352  {
353  $this->invalid_links[] = $a_link;
354  }
355 
356 
357  function __appendLogMessage($a_string)
358  {
359  $this->log_messages[] = $a_string;
360  }
362  {
363  return $this->log_messages = array();
364  }
365 
366  function __getLinks($a_page)
367  {
368  $matches = array();
369 
370  $pattern_complete = '/<ExtLink Href="([^"]*)">/';
371  if(preg_match_all($pattern_complete,$a_page['content'],$matches))
372  {
373  for($i = 0;$i < count($matches[0]); ++$i)
374  {
375  $url_data = @parse_url($matches[1][$i]);
376  // continue if mailto link
377  if($url_data['scheme'] == 'mailto')
378  {
379  continue;
380  }
381 
382  // PUH, HTTP_REQUEST needs a beginning http://
383  if(!$url_data['scheme'])
384  {
385  $matches[1][$i] = 'http://'.$matches[1][$i];
386  }
387 
388  $lm_id = $this->__getObjIdByPageId($a_page['page_id']);
389  $link[] = array('page_id' => $a_page['page_id'],
390  'obj_id' => $lm_id,
391  'type' => $a_page['type'],
392  'complete' => $matches[1][$i],
393  'scheme' => isset($url_data['scheme']) ? $url_data['scheme'] : 'http',
394  'host' => isset($url_data['host']) ? $url_data['host'] : $url_data['path']);
395  }
396  }
397 
398  return $link ? $link : array();
399  }
400 
402  {
403  global $objDefinition;
404 
405  include_once 'Modules/WebResource/classes/class.ilLinkResourceItems.php';
406 
407  $link_res_obj = new ilLinkResourceItems($this->getObjId());
408 
409  foreach($check_links = $link_res_obj->getCheckItems($this->getCheckPeriod()) as $item_data)
410  {
411  // #10091 - internal
412  if(strpos($item_data['target'], '|'))
413  {
414  $parts = explode('|', $item_data['target']);
415  if(sizeof($parts) == 2 &&
416  is_numeric($parts[1]) &&
417  $objDefinition->isAllowedInRepository($parts[0]))
418  {
419  $link[] = array('page_id' => $item_data['link_id'],
420  'obj_id' => $this->getObjId(),
421  'type' => 'webr',
422  'complete' => $item_data['target'],
423  'scheme' => 'internal',
424  'obj_type' => $parts[0],
425  'ref_id' => $parts[1]);
426  continue;
427  }
428  }
429 
430  // external
431  $url_data = @parse_url($item_data['target']);
432 
433  // PUH, HTTP_REQUEST needs a beginning http://
434  if(!$url_data['scheme'])
435  {
436  $item_data['target'] = 'http://'.$item_data['target'];
437  }
438 
439  $link[] = array('page_id' => $item_data['link_id'],
440  'obj_id' => $this->getObjId(),
441  'type' => 'webr',
442  'complete' => $item_data['target'],
443  'scheme' => isset($url_data['scheme']) ? $url_data['scheme'] : 'http',
444  'host' => isset($url_data['host']) ? $url_data['host'] : $url_data['path']);
445  }
446  return $link ? $link : array();
447  }
448 
449 
450 
451  function __validateLinks($a_links)
452  {
453  global $tree;
454 
455  if(!@include_once('HTTP/Request.php'))
456  {
457  $this->__appendLogMessage('LinkChecker: Pear HTTP_Request is not installed. Aborting');
458 
459  return array();
460  }
461 
462  foreach($a_links as $link)
463  {
464  // #10091 - internal
465  if($link['scheme'] == 'internal')
466  {
467  $obj_id = ilObject::_lookupObjId($link['ref_id']);
468  if(!$obj_id ||
469  ilObject::_lookupType($obj_id) != $link['obj_type'] ||
470  $tree->isDeleted($link['ref_id']))
471  {
472  $invalid[] = $link;
473  }
474  }
475  // external
476  else
477  {
478  if(gethostbyname($link['host']) == $link['host'])
479  {
480  $invalid[] = $link;
481  continue;
482  }
483 
484  if($link['scheme'] !== 'http' and $link['scheme'] !== 'https')
485  {
486  continue;
487  }
488 
489  require_once './Services/Http/classes/class.ilProxySettings.php';
490 
491  if(ilProxySettings::_getInstance()->isActive())
492  {
493  $options = array('proxy_host' => ilProxySettings::_getInstance()->getHost(),
494  'proxy_port' => ilProxySettings::_getInstance()->getPort());
495  }
496  else
497  {
498  $options = array();
499  }
500 
501  $req = new HTTP_Request($link['complete'], $options);
502  $req->sendRequest();
503 
504  switch($req->getResponseCode())
505  {
506  // EVERYTHING OK
507  case '200':
508  // In the moment 301 will be handled as ok
509  case '301':
510  case '302':
511  break;
512 
513  default:
514  $link['http_status_code'] = $req->getResponseCode();
515  $invalid[] = $link;
516  break;
517  }
518  }
519  }
520  return $invalid ? $invalid : array();
521  }
522 
523  function __getObjIdByPageId($a_page_id)
524  {
525  $query = "SELECT lm_id FROM lm_data ".
526  "WHERE obj_id = '".$a_page_id."'";
527 
528  $row = $this->db->getRow($query,DB_FETCHMODE_OBJECT);
529 
530  return $row->lm_id ? $row->lm_id : 0;
531  }
532 
533  function __isInvalid($a_page_id, $a_url)
534  {
535  foreach($this->getInvalidLinks() as $link)
536  {
537  if($link['page_id'] == $a_page_id and
538  substr($link['complete'],0,255) == $a_url)
539  {
540  return true;
541  }
542  }
543  return false;
544  }
545 
546  function __saveInDB()
547  {
548  global $ilDB;
549 
550  if($this->getMailStatus())
551  {
552  $this->__checkNotify();
553  }
554  $this->__clearDBData();
555 
556 
557  foreach($this->getInvalidLinks() as $link)
558  {
559  $query = "INSERT INTO link_check (obj_id,page_id,url,parent_type,http_status_code,last_check) ".
560  "VALUES ( ".
561  $ilDB->quote($link['obj_id'],'integer').", ".
562  $ilDB->quote($link['page_id'],'integer').", ".
563  $ilDB->quote(substr($link['complete'],0,255),'text').", ".
564  $ilDB->quote($link['type'],'text').", ".
565  $ilDB->quote($link['http_status_code'] ? $link['http_status_code'] : 0,'integer').", ".
566  $ilDB->quote(time(),'integer')." ".
567  ")";
568  $res = $ilDB->manipulate($query);
569  }
570  }
571 
572  function __checkNotify()
573  {
574  global $ilDB;
575 
576  foreach($this->getInvalidLinks() as $link)
577  {
578  $query = "SELECT * FROM link_check ".
579  "WHERE page_id = ".$ilDB->quote($link['page_id'],'integer')." ".
580  "AND url = ".$ilDB->quote(substr($link['complete'],0,255),'text')." ";
581  $res = $ilDB->query($query);
582 
583  if(!$res->numRows())
584  {
585  $this->notify[$link["obj_id"]][] = array('page_id' => $link['page_id'],
586  'url' => $link['complete']);
587  }
588  }
589  }
590 
591 
592  function __clearDBData()
593  {
594  global $ilDB;
595 
596  if($this->getValidateAll())
597  {
598  $query = "DELETE FROM link_check";
599  }
600  else
601  {
602  $query = "DELETE FROM link_check ".
603  "WHERE obj_id = ".$ilDB->quote($this->getObjId(),'integer');
604  }
605  $res = $ilDB->manipulate($query);
606 
607  return true;
608  }
609 }
610 ?>