1#!/usr/bin/php
2<?php
3
4chdir(dirname(__FILE__));
5require_once 'common.php';
6require_once '../tests/path2class.func.php';
7require_once '../library/HTMLPurifier/Bootstrap.php';
8assertCli();
9
10/**
11 * @file
12 * Generates an include stub for users who do not want to use the autoloader.
13 * When new files are added to HTML Purifier's main codebase, this file should
14 * be called.
15 */
16
17chdir(dirname(__FILE__) . '/../library/');
18$FS = new FSTools();
19
20$exclude_dirs = array(
21    'HTMLPurifier/Language/',
22    'HTMLPurifier/ConfigSchema/',
23    'HTMLPurifier/Filter/',
24    'HTMLPurifier/Printer/',
25    /* These should be excluded, but need to have ConfigSchema support first
26
27    */
28);
29$exclude_files = array(
30    'HTMLPurifier/Lexer/PEARSax3.php',
31    'HTMLPurifier/Lexer/PH5P.php',
32    'HTMLPurifier/Printer.php',
33);
34
35// Determine what files need to be included:
36echo 'Scanning for files... ';
37$raw_files = $FS->globr('.', '*.php');
38if (!$raw_files) throw new Exception('Did not find any PHP source files');
39$files = array();
40foreach ($raw_files as $file) {
41    $file = substr($file, 2); // rm leading './'
42    if (strncmp('standalone/', $file, 11) === 0) continue; // rm generated files
43    if (substr_count($file, '.') > 1) continue; // rm meta files
44    $ok = true;
45    foreach ($exclude_dirs as $dir) {
46        if (strncmp($dir, $file, strlen($dir)) === 0) {
47            $ok = false;
48            break;
49        }
50    }
51    if (!$ok) continue; // rm excluded directories
52    if (in_array($file, $exclude_files)) continue; // rm excluded files
53    $files[] = $file;
54}
55echo "done!\n";
56
57// Reorder list so that dependencies are included first:
58
59/**
60 * Returns a lookup array of dependencies for a file.
61 *
62 * @note This function expects that format $name extends $parent on one line
63 *
64 * @param string $file
65 *      File to check dependencies of.
66 * @return array
67 *      Lookup array of files the file is dependent on, sorted accordingly.
68 */
69function get_dependency_lookup($file)
70{
71    static $cache = array();
72    if (isset($cache[$file])) return $cache[$file];
73    if (!file_exists($file)) {
74        echo "File doesn't exist: $file\n";
75        return array();
76    }
77    $fh = fopen($file, 'r');
78    $deps = array();
79    while (!feof($fh)) {
80        $line = fgets($fh);
81        if (strncmp('class', $line, 5) === 0) {
82            // The implementation here is fragile and will break if we attempt
83            // to use interfaces. Beware!
84            $arr = explode(' extends ', trim($line, ' {'."\n\r"), 2);
85            if (count($arr) < 2) break;
86            $parent = $arr[1];
87            $dep_file = HTMLPurifier_Bootstrap::getPath($parent);
88            if (!$dep_file) break;
89            $deps[$dep_file] = true;
90            break;
91        }
92    }
93    fclose($fh);
94    foreach (array_keys($deps) as $file) {
95        // Extra dependencies must come *before* base dependencies
96        $deps = get_dependency_lookup($file) + $deps;
97    }
98    $cache[$file] = $deps;
99    return $deps;
100}
101
102/**
103 * Sorts files based on dependencies. This function is lazy and will not
104 * group files with dependencies together; it will merely ensure that a file
105 * is never included before its dependencies are.
106 *
107 * @param $files
108 *      Files array to sort.
109 * @return
110 *      Sorted array ($files is not modified by reference!)
111 */
112function dep_sort($files)
113{
114    $ret = array();
115    $cache = array();
116    foreach ($files as $file) {
117        if (isset($cache[$file])) continue;
118        $deps = get_dependency_lookup($file);
119        foreach (array_keys($deps) as $dep) {
120            if (!isset($cache[$dep])) {
121                $ret[] = $dep;
122                $cache[$dep] = true;
123            }
124        }
125        $cache[$file] = true;
126        $ret[] = $file;
127    }
128    return $ret;
129}
130
131$files = dep_sort($files);
132
133// Build the actual include stub:
134
135$version = trim(file_get_contents('../VERSION'));
136
137// stub
138$php = "<?php
139
140/**
141 * @file
142 * This file was auto-generated by generate-includes.php and includes all of
143 * the core files required by HTML Purifier. Use this if performance is a
144 * primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
145 * FILE, changes will be overwritten the next time the script is run.
146 *
147 * @version $version
148 *
149 * @warning
150 *      You must *not* include any other HTML Purifier files before this file,
151 *      because 'require' not 'require_once' is used.
152 *
153 * @warning
154 *      This file requires that the include path contains the HTML Purifier
155 *      library directory; this is not auto-set.
156 */
157
158";
159
160foreach ($files as $file) {
161    $php .= "require '$file';" . PHP_EOL;
162}
163
164echo "Writing HTMLPurifier.includes.php... ";
165file_put_contents('HTMLPurifier.includes.php', $php);
166echo "done!\n";
167
168$php = "<?php
169
170/**
171 * @file
172 * This file was auto-generated by generate-includes.php and includes all of
173 * the core files required by HTML Purifier. This is a convenience stub that
174 * includes all files using dirname(__FILE__) and require_once. PLEASE DO NOT
175 * EDIT THIS FILE, changes will be overwritten the next time the script is run.
176 *
177 * Changes to include_path are not necessary.
178 */
179
180\$__dir = dirname(__FILE__);
181
182";
183
184foreach ($files as $file) {
185    $php .= "require_once \$__dir . '/$file';" . PHP_EOL;
186}
187
188echo "Writing HTMLPurifier.safe-includes.php... ";
189file_put_contents('HTMLPurifier.safe-includes.php', $php);
190echo "done!\n";
191
192// vim: et sw=4 sts=4
193