7b987e3280fa0b298c7c0f9b2ef774eb15cc5a87
[phinde.git] / src / phinde / LinkExtractor / Html.php
1 <?php
2 namespace phinde\LinkExtractor;
3
4 use phinde\LinkInfo;
5 use phinde\Helper;
6
7 class Html
8 {
9     public function extract(\HTTP_Request2_Response $res)
10     {
11         $url = $res->getEffectiveUrl();
12
13         $linkInfos = array();
14
15         //FIXME: mime type switch for cdata
16         $doc = new \DOMDocument();
17         //@ to hide parse warning messages in invalid html
18         @$doc->loadHTML($res->getBody());
19
20         //FIXME: extract base url from html
21         $base = new \Net_URL2($url);
22
23         $dx = new \DOMXPath($doc);
24
25         $xbase = $dx->evaluate('/html/head/base[@href]')->item(0);
26         if ($xbase) {
27             $base = $base->resolve(
28                 $xbase->attributes->getNamedItem('href')->textContent
29             );
30         }
31
32         $meta = $dx->evaluate('/html/head/meta[@name="robots" and @content]')
33             ->item(0);
34         if ($meta) {
35             $robots = $meta->attributes->getNamedItem('content')->textContent;
36             foreach (explode(',', $robots) as $value) {
37                 if (trim($value) == 'nofollow') {
38                     //we shall not follow the links
39                     return array();
40                 }
41             }
42         }
43
44         $links = $dx->evaluate('//a');
45         //FIXME: link rel, img, video
46
47         $alreadySeen = array($url => true);
48
49         foreach ($links as $link) {
50             $linkTitle = Helper::sanitizeTitle($link->textContent);
51             $href = '';
52             foreach ($link->attributes as $attribute) {
53                 if ($attribute->name == 'href') {
54                     $href = $attribute->textContent;
55                 } else if ($attribute->name == 'rel') {
56                     foreach (explode(',', $attribute->textContent) as $value) {
57                         if (trim($value) == 'nofollow') {
58                             //we shall not follow this link
59                             continue 3;
60                         }
61                     }
62                 }
63             }
64             if ($href == '' || $href{0} == '#') {
65                 //link on this page
66                 continue;
67             }
68
69             $linkUrlObj = $base->resolve($href);
70             $linkUrlObj->setFragment(false);
71             $linkUrl    = (string) $linkUrlObj;
72             if (isset($alreadySeen[$linkUrl])) {
73                 continue;
74             }
75
76             switch ($linkUrlObj->getScheme()) {
77             case 'http':
78             case 'https':
79                 break;
80             default:
81                 continue 2;
82             }
83
84             //FIXME: check target type
85             $linkInfos[] = new LinkInfo(
86                $linkUrl, $linkTitle, $url
87             );
88             $alreadySeen[$linkUrl] = true;
89         }
90
91         return $linkInfos;
92     }
93 }
94 ?>