Fix E_NOTICE: Only variables should be passed by reference
[phorkie.git] / src / phorkie / File.php
1 <?php
2 namespace phorkie;
3
4 class File
5 {
6     /**
7      * Path to the file, relative to repository work directory
8      *
9      * @var string
10      */
11     public $path;
12
13     /**
14      * Repository this file belongs to
15      *
16      * @var string
17      */
18     public $repo;
19
20     /**
21      * Commit revision this file is at
22      */
23     public $hash;
24
25     public function __construct($path, Repository $repo = null)
26     {
27         $this->path = $path;
28         $this->repo = $repo;
29     }
30
31     /**
32      * Get filename relative to the repository path
33      *
34      * @return string
35      */
36     public function getFilename()
37     {
38         return $this->path;
39     }
40
41     /**
42      * Get the filename usable as HTML anchor.
43      *
44      * @return string
45      */
46     function getAnchorName()
47     {
48         return str_replace(' ', '-', $this->getFilename());
49     }
50
51     /**
52      * Return the full path to the file
53      *
54      * @return string
55      */
56     public function getFullPath()
57     {
58         return $this->repo->workDir . '/' . $this->path;
59     }
60
61     /**
62      * Get file extension without dot
63      *
64      * @return string
65      */
66     public function getExt()
67     {
68         return strtolower(substr($this->path, strrpos($this->path, '.') + 1));
69     }
70
71     public function getContent()
72     {
73         if ($this->repo->hash) {
74             //quick hack until https://pear.php.net/bugs/bug.php?id=19385 is fixed
75             $cmd = new GitCommandBinary($this->repo->getVc());
76             $cmd->setSubCommand('show');
77             return $cmd
78                 ->addArgument($this->repo->hash . ':' . $this->path)
79                 ->execute();
80         }
81
82         return file_get_contents($this->getFullPath());
83     }
84
85     public function getRenderedContent(Tool_Result $res = null)
86     {
87         $cache = new Renderer_Cache();
88         return $cache->toHtml($this, $res);
89     }
90
91     /**
92      * Get a link to the file
93      *
94      * @param string $type   Link type. Supported are:
95      *                       - "display"
96      *                       - "raw"
97      *                       - "tool"
98      * @param string $option Additional option, e.g. tool name
99      * @param boolean $full   Return full URL or normal relative
100      *
101      * @return string
102      */
103     public function getLink($type, $option = null, $full = false)
104     {
105         if ($type == 'raw') {
106             if ($this->repo->hash === null) {
107                 $link = $this->repo->id . '/raw/' . $this->getFilename();
108             } else {
109                 $link = $this->repo->id . '/rev-raw/' . $this->repo->hash
110                     . '/' . $this->getFilename();
111             }
112         } else if ($type == 'tool') {
113             $link = $this->repo->id
114                 . '/tool/' . $option
115                 . '/' . $this->getFilename();
116         } else if ($type == 'display') {
117             $link = $this->repo->id . '#' . $this->getFilename();
118         } else {
119             throw new Exception('Unknown type');
120         }
121
122         if ($full) {
123             $link = Tools::fullUrl($link);
124         }
125         return $link;
126     }
127
128     /**
129      * @return string Mime type of file, NULL if no type detected
130      */
131     public function getMimeType()
132     {
133         $ext = $this->getExt();
134         if (isset($GLOBALS['phorkie']['languages'][$ext])) {
135             return $GLOBALS['phorkie']['languages'][$ext]['mime'];
136         }
137
138         $mte = new \MIME_Type_Extension();
139         $type = $mte->getMIMEType($this->getFilename());
140         if (!\PEAR::isError($type)) {
141             return $type;
142         }
143         return null;
144     }
145
146     /**
147      * @return array Array of Tool_Info objects
148      */
149     public function getToolInfos()
150     {
151         if ($this->repo->hash !== null) {
152             return array();
153         }
154
155         $tm = new Tool_Manager();
156         return $tm->getSuitable($this);
157     }
158
159     /**
160      * Tells if the file contains textual content and is editable.
161      *
162      * @return boolean
163      */
164     public function isText()
165     {
166         $ext = $this->getExt();
167         if ($ext == '') {
168             return $this->isNonBinary();
169         }
170
171         $type = $this->getMimeType();
172         if ($type === null) {
173             return $this->isNonBinary();
174         }
175         return substr($type, 0, 5) === 'text/'
176             || $type == 'application/javascript'
177             || substr($type, -4) == '+xml'
178             || substr($type, -5) == '+json';
179     }
180
181     /**
182      * Look at the file's bytes and guess if it's binary or not.
183      *
184      * @return boolean True if it's most likely plain text
185      */
186     public function isNonBinary()
187     {
188         $fp = fopen($this->getFullPath(), 'r');
189         if (!$fp) {
190             return false;
191         }
192
193         //When multibyte extension is not installed,
194         // we only allow files with ASCII characters.
195         // Files with UTF-8 characters will not be detected as text.
196         $hasMb = function_exists('mb_detect_encoding');
197
198         $pos = 0;
199         $data = '';
200         while (false !== ($char = fgetc($fp)) && ++$pos < 100) {
201             $data .= $char;
202             if (!$hasMb && ord($char) > 128) {
203                 fclose($fp);
204                 return false;
205             }
206         }
207         fclose($fp);
208
209         if (!$hasMb) {
210             return true;
211         }
212
213         if (mb_detect_encoding($data) === false) {
214             return false;
215         }
216         return true;
217     }
218 }
219
220 ?>