Use title of remote paste for forked one; use page title as fallback
[phorkie.git] / src / phorkie / ForkRemote.php
1 <?php
2 namespace phorkie;
3
4 class ForkRemote
5 {
6     /**
7      * Contains error message when parse() failed
8      */
9     public $error;
10
11     protected $url;
12
13     /**
14      * Array with keys (URL title) and values (arrays of urls)
15      * Only supported URLs are included.
16      *
17      * @var array
18      */
19     protected $arGitUrls;
20
21
22
23     public function __construct($url)
24     {
25         $this->url = trim($url);
26     }
27
28     public function parse()
29     {
30         if ($this->url == '') {
31             $this->error = 'Empty fork URL';
32             return false;
33         }
34
35         $arUrl  = parse_url($this->url);
36         $scheme = isset($arUrl['scheme']) ? $arUrl['scheme'] : '';
37
38         if ($scheme == 'https' && isset($arUrl['host'])
39             && $arUrl['host'] == 'gist.github.com'
40         ) {
41             $this->arGitUrls[][] = 'git://gist.github.com/'
42                 . ltrim($arUrl['path'], '/') . '.git';
43             return true;
44         }
45
46         switch ($scheme) {
47         case 'git':
48             //clearly a git url
49             $this->arGitUrls = array(array($this->url));
50             return true;
51
52         case 'ssh':
53             //FIXME: maybe loosen this when we know how to skip the
54             //"do you trust this server" question of ssh
55             $this->error = 'ssh:// URLs are not supported';
56             return false;
57
58         case 'http':
59         case 'https':
60             return $this->extractUrlsFromHtml($this->url);
61         }
62
63         $this->error = 'Unknown URLs scheme: ' . $scheme;
64         return false;
65     }
66
67     protected function extractUrlsFromHtml($url)
68     {
69         //HTML is not necessarily well-formed, and Gitorious has many problems
70         // in this regard
71         //$sx = simplexml_load_file($url);
72         libxml_use_internal_errors(true);
73         $sx = simplexml_import_dom(\DomDocument::loadHtmlFile($url));
74         $elems = $sx->xpath('//*[@rel="vcs-git"]');
75         $titles = $sx->xpath('/html/head/title');
76         $pageTitle = $this->cleanPageTitle((string) reset($titles));
77
78         $count = $anonymous = 0;
79         foreach ($elems as $elem) {
80             if (!isset($elem['href'])) {
81                 continue;
82             }
83             $str = (string)$elem;
84             if (isset($elem['title'])) {
85                 //<link href=".." rel="vcs-git" title="title" />
86                 $title = (string)$elem['title'];
87             } else if ($str != '') {
88                 //<a href=".." rel="vcs-git">title</a>
89                 $title = $str;
90             } else if ($pageTitle != '') {
91                 $title = $pageTitle;
92             } else {
93                 $title = 'Unnamed repository #' . ++$anonymous;
94             }
95             $url = (string)$elem['href'];
96             if ($this->isSupported($url)) {
97                 ++$count;
98                 $this->arGitUrls[$title][] = $url;
99             }
100         }
101
102         if ($count > 0) {
103             return true;
104         }
105
106         $this->error = 'No git:// clone URL found';
107         return false;
108     }
109
110     /**
111      * Iterate through all git urls and return one if there is only
112      * one supported one.
113      *
114      * @return mixed Boolean false or array with keys "url" and "title"
115      */
116     public function getUniqueGitUrl()
117     {
118         $nFound = 0;
119         foreach ($this->arGitUrls as $title => $arUrls) {
120             foreach ($arUrls as $url) {
121                 $nFound++;
122                 $uniqueUrl = array('url' => $url, 'title' => $title);
123             }
124         }
125
126         if ($nFound == 1) {
127             return $uniqueUrl;
128         }
129         return false;
130     }
131
132     public function getGitUrls()
133     {
134         return $this->arGitUrls;
135     }
136
137     /**
138      * Get the URL from which the git URL was derived, often
139      * the HTTP URL.
140      *
141      * @return string
142      */
143     public function getUrl()
144     {
145         return $this->url;
146     }
147
148     public function setUrl($url)
149     {
150         $this->url = $url;
151     }
152
153     public function isSupported($url)
154     {
155         $scheme = parse_url($url, PHP_URL_SCHEME);
156         return $scheme == 'git'
157             || $scheme == 'http' || $scheme == 'https';
158     }
159
160     /**
161      * Remove application names from HTML page titles
162      *
163      * @param string $title HTML page title
164      *
165      * @return string Cleaned HTML page title
166      */
167     protected function cleanPageTitle($title)
168     {
169         $title = trim($title);
170         if (substr($title, -9) == '- phorkie') {
171             $title = trim(substr($title, 0, -9));
172         }
173
174         return $title;
175     }
176 }
177
178 ?>