26cf9944e4aa67eb8691019d6ff92500f30e66fc
[phinde.git] / bin / crawl.php
1 #!/usr/bin/env php
2 <?php
3 namespace phinde;
4
5 set_include_path(__DIR__ . '/../src/' . PATH_SEPARATOR . get_include_path());
6 require_once __DIR__ . '/../data/config.php';
7 require_once 'HTTP/Request2.php';
8 require_once 'Elasticsearch.php';
9 require_once 'Elasticsearch/Request.php';
10 require_once 'Net/URL2.php';
11 require_once 'functions.php';
12
13 $supportedCrawlTypes = array(
14     'text/html', 'application/xhtml+xml'
15 );
16
17
18 if ($argc < 2) {
19     echo "No URL given\n";
20     exit(1);
21 }
22
23 $es = new Elasticsearch($GLOBALS['phinde']['elasticsearch']);
24
25 $url = $argv[1];
26 if (!isUrlAllowed($url)) {
27     echo "Domain is not allowed; not crawling\n";
28     exit(2);
29 }
30
31
32 $req = new \HTTP_Request2($url);
33 //FIXME: send supported mime types in header
34 $res = $req->send();
35 if ($res->getStatus() !== 200) {
36     echo "Response code is not 200 but " . $res->getStatus() . ", stopping\n";
37     exit(3);
38 }
39 $mimetype = explode(';', $res->getHeader('content-type'))[0];
40 if (!in_array($mimetype, $supportedCrawlTypes)) {
41     echo "MIME type not supported for crawling: $mimetype\n";
42     exit(4);
43 }
44
45 //FIXME: mime type switch for cdata
46 $doc = new \DOMDocument();
47 //@ to hide parse warning messages in invalid html
48 @$doc->loadHTMLFile($url);
49
50 //FIXME: extract base url from html
51 $base = new \Net_URL2($url);
52
53 $xpath = new \DOMXPath($doc);
54 $links = $xpath->evaluate('//a');
55 //FIXME: link rel, img, video
56
57 $alreadySeen = array();
58
59 foreach ($links as $link) {
60     $linkTitle = $link->textContent;
61     $href = '';
62     foreach ($link->attributes as $attribute) {
63         if ($attribute->name == 'href') {
64             $href = $attribute->textContent;
65         }
66     }
67     if ($href == '' || $href{0} == '#') {
68         //link on this page
69         continue;
70     }
71
72     $linkUrlObj = $base->resolve($href);
73     $linkUrlObj->setFragment(false);
74     $linkUrl    = (string) $linkUrlObj;
75     if (isset($alreadySeen[$linkUrl])) {
76         continue;
77     }
78
79     switch ($linkUrlObj->getScheme()) {
80     case 'http':
81     case 'https':
82         break;
83     default:
84         continue 2;
85     }
86
87     if ($es->isKnown($linkUrl)) {
88         continue;
89     }
90
91     //FIXME: check target type
92     //FIXME: check nofollow
93     //var_dump($linkTitle, $linkUrl);
94     $es->markQueued($linkUrl);
95     addToIndex($linkUrl, $linkTitle, $url);
96     if (isUrlAllowed($linkUrl)) {
97         addToCrawl($linkUrl);
98     }
99     $alreadySeen[$linkUrl] = true;
100 }
101
102 function addToIndex($linkUrl, $linkTitle, $sourceUrl)
103 {
104     echo "Queuing for indexing: $linkUrl\n";
105     $gmclient = new \GearmanClient();
106     $gmclient->addServer('127.0.0.1');
107     $gmclient->doBackground(
108         'phinde_index',
109         serialize(
110             array(
111                 'url'    => $linkUrl,
112                 'title'  => $linkTitle,
113                 'source' => $sourceUrl
114             )
115         )
116     );
117     if ($gmclient->returnCode() != GEARMAN_SUCCESS) {
118         echo 'Error queueing URL indexing for '
119             . $linkUrl . "\n"
120             . 'Error code: ' . $gmclient->returnCode() . "\n";
121         exit(2);
122     }
123 }
124
125 function addToCrawl($linkUrl)
126 {
127     echo "Queuing for crawling: $linkUrl\n";
128     $gmclient = new \GearmanClient();
129     $gmclient->addServer('127.0.0.1');
130     $gmclient->doBackground(
131         'phinde_crawl',
132         serialize(
133             array(
134                 'url' => $linkUrl
135             )
136         )
137     );
138     if ($gmclient->returnCode() != GEARMAN_SUCCESS) {
139         echo 'Error queueing URL crawling for '
140             . $linkUrl . "\n"
141             . 'Error code: ' . $gmclient->returnCode() . "\n";
142         exit(2);
143     }
144 }
145 ?>