Remove trailing whitespace.
[xhtml-compiler.git] / XHTMLCompiler / Directory.php
blob61f0963fd76a1d5786dc58ce8483c3f3804d538d
1 <?php
3 /**
4 * Represents a directory in the filesystem
5 */
6 class XHTMLCompiler_Directory
9 /** Location of directory this object represents, w/o trailing slash */
10 protected $name;
12 /** Non-blank location of directory, safe for directory handling functions */
13 protected $safeName;
15 /**
16 * Path to directory you wish to instantiate.
18 public function __construct($name) {
19 $xc = XHTMLCompiler::getInstance();
20 $php = XHTMLCompiler::getPHPWrapper();
22 $name = str_replace('\\', '/', $name); // normalize \ to /
23 $l = strlen($name) - 1; // index of last character
24 if ($l >= 0 && $name[$l] == '/') $name = substr($name, 0, $l); // truncate trailing slash
25 if ($name === '.') $name = ''; // we want the "unsafe" but pretty version
26 $safe_name = ($name === '') ? '.' : $name;
27 if (!$php->isDir($safe_name)) {
28 throw new Exception("Directory $safe_name does not exist");
30 $this->name = $name;
31 $this->safeName = $safe_name;
34 /**
35 * Returns name of directory without trailing slash
36 * @note This function works in all cases, but can be slightly
37 * redundant if the application is prepending it to
38 * a filename (compare index.html versus ./index.html)
40 public function getName() {return $this->safeName;}
42 /**
43 * Returns name of directory with trailing slash, prepared for
44 * a filename to be appended (s = slash, it is NOT safe)
45 * @note If the directory is the current working directory, a blank
46 * string is returned instead. This makes this method good
47 * for web-contexts, and reasonably well when appending it
48 * onto filenames, but will NOT work if you're actually trying
49 * to refer to a directory (see getNAme() for that)
51 public function getSName() {
52 return ($this->name === '') ? '' : $this->name . '/';
55 /**
56 * Recursively scans directory for files
57 * @return Tree of files in the directory, file => size
59 public function getTree() {
60 $dir = new RecursiveDirectoryIterator($this->safeName);
61 $tree = array();
62 $dirs = array(array($dir, &$tree));
64 for($i = 0; $i < count($dirs); ++$i) {
65 $d =& $dirs[$i][0]; // current directory iterator
66 $tier =& $dirs[$i][1]; // current directory tree to write to
67 for($d->rewind(); $d->valid(); $d->next()) {
68 if ($d->isDir()) {
69 // initialize new directory tree
70 $tier[$d->getFilename()] = array();
71 // file away another directory to process
72 $dirs[] = array($d->getChildren(), &$tier[$d->getFilename()]);
73 } else {
74 // add the file to the directory tree
75 $tier[$d->getFilename()] = $d->getSize();
80 return $tree;
83 /**
84 * Scans directory recursively for files with a certain file extension
85 * @param $ext_match Extension with period to look for, cannot have
86 * more than one period within it
87 * @return List of matching files, with fully qualified relative
88 * paths (not tree format)
90 public function scanRecursively($ext_match) {
91 $tree = $this->getTree();
92 $dirs = array(array('', &$tree));
93 $ret = array();
94 for ($i = 0; $i < count($dirs); ++$i) {
95 $base = $dirs[$i][0]; // base directory prefix
96 $tier = $dirs[$i][1]; // tree node we're reading from
97 foreach ($tier as $name => $contents) {
98 if (is_array($contents)) {
99 // directory
100 $dirs[] = array($base . $name . '/', $contents);
101 } else {
102 // name
103 $ext = strrchr($name, '.');
104 if ($ext != $ext_match) continue;
105 $ret[] = $this->getSName() . $base . $name;
109 return $ret;
113 * Scans just the current directory for files matching extension
114 * @param $ext_match Extension with period to look for, cannot have
115 * more than one period within it
116 * @return List of matching files
118 public function scanFlat($ext_match) {
119 $files = scandir($this->safeName);
120 $ret = array();
121 foreach ($files as $name) {
122 if (empty($name) || $name[0] == '.') continue;
123 $ext = strrchr($name, '.');
124 if ($ext != $ext_match) continue;
125 $ret[] = $this->getSName() . $name;
127 return $ret;
131 * Scans directory for files with matching extension
132 * @param $ext_match File extension to match
133 * @param $recursive Whether or not to search recursively
135 public function scan($ext, $recursive) {
136 if ($recursive) return $this->scanRecursively($ext);
137 else return $this->scanFlat($ext);
140 public function getParent() {
141 $last_slash = strrpos($this->name, '/');
142 $parent = substr($this->name, 0, $last_slash);
143 return new XHTMLCompiler_Directory($parent);
146 public function getFile($filename) {
147 return new XHTMLCompiler_File($this->getSName() . $filename);
150 public function isAllowed() {
151 $xc = XHTMLCompiler::getInstance();
152 $php = XHTMLCompiler::getPHPWrapper();
153 $allowed_dirs = $xc->getConf("allowed_dirs");
154 $dir = realpath($this->safeName);
155 if ($dir[strlen($dir)-1] == '/') $dir = substr($dir, 0, -1);
156 $ok = false;
158 foreach ($allowed_dirs as $allowed_dir => $recursive) {
159 $allowed_dir = $php->realpath($allowed_dir); // factor out!
160 if (!is_string($allowed_dir)) continue;
161 if ($dir === $allowed_dir) {
162 $ok = true;
163 break;
164 // slash is required to prevent $allowed_dir = 'subdir' from
165 // matching $dir = 'subdirectory', thanks Mordred!
166 } elseif (strpos($dir, $allowed_dir . '/') === 0 && $recursive) {
167 $ok = true;
168 break;
171 return $ok;