| [21] | 1 | <?php |
|---|
| 2 | |
|---|
| 3 | /** |
|---|
| 4 | * Parses string hash files. File format is as such: |
|---|
| 5 | * |
|---|
| 6 | * DefaultKeyValue |
|---|
| 7 | * KEY: Value |
|---|
| 8 | * KEY2: Value2 |
|---|
| 9 | * --MULTILINE-KEY-- |
|---|
| 10 | * Multiline |
|---|
| 11 | * value. |
|---|
| 12 | * |
|---|
| 13 | * Which would output something similar to: |
|---|
| 14 | * |
|---|
| 15 | * array( |
|---|
| 16 | * 'ID' => 'DefaultKeyValue', |
|---|
| 17 | * 'KEY' => 'Value', |
|---|
| 18 | * 'KEY2' => 'Value2', |
|---|
| 19 | * 'MULTILINE-KEY' => "Multiline\nvalue.\n", |
|---|
| 20 | * ) |
|---|
| 21 | * |
|---|
| 22 | * We use this as an easy to use file-format for configuration schema |
|---|
| 23 | * files, but the class itself is usage agnostic. |
|---|
| 24 | * |
|---|
| 25 | * You can use ---- to forcibly terminate parsing of a single string-hash; |
|---|
| 26 | * this marker is used in multi string-hashes to delimit boundaries. |
|---|
| 27 | */ |
|---|
| 28 | class HTMLPurifier_StringHashParser |
|---|
| 29 | { |
|---|
| 30 | |
|---|
| 31 | public $default = 'ID'; |
|---|
| 32 | |
|---|
| 33 | /** |
|---|
| 34 | * Parses a file that contains a single string-hash. |
|---|
| 35 | */ |
|---|
| 36 | public function parseFile($file) { |
|---|
| 37 | if (!file_exists($file)) return false; |
|---|
| 38 | $fh = fopen($file, 'r'); |
|---|
| 39 | if (!$fh) return false; |
|---|
| 40 | $ret = $this->parseHandle($fh); |
|---|
| 41 | fclose($fh); |
|---|
| 42 | return $ret; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | /** |
|---|
| 46 | * Parses a file that contains multiple string-hashes delimited by '----' |
|---|
| 47 | */ |
|---|
| 48 | public function parseMultiFile($file) { |
|---|
| 49 | if (!file_exists($file)) return false; |
|---|
| 50 | $ret = array(); |
|---|
| 51 | $fh = fopen($file, 'r'); |
|---|
| 52 | if (!$fh) return false; |
|---|
| 53 | while (!feof($fh)) { |
|---|
| 54 | $ret[] = $this->parseHandle($fh); |
|---|
| 55 | } |
|---|
| 56 | fclose($fh); |
|---|
| 57 | return $ret; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | /** |
|---|
| 61 | * Internal parser that acepts a file handle. |
|---|
| 62 | * @note While it's possible to simulate in-memory parsing by using |
|---|
| 63 | * custom stream wrappers, if such a use-case arises we should |
|---|
| 64 | * factor out the file handle into its own class. |
|---|
| 65 | * @param $fh File handle with pointer at start of valid string-hash |
|---|
| 66 | * block. |
|---|
| 67 | */ |
|---|
| 68 | protected function parseHandle($fh) { |
|---|
| 69 | $state = false; |
|---|
| 70 | $single = false; |
|---|
| 71 | $ret = array(); |
|---|
| 72 | do { |
|---|
| 73 | $line = fgets($fh); |
|---|
| 74 | if ($line === false) break; |
|---|
| 75 | $line = rtrim($line, "\n\r"); |
|---|
| 76 | if (!$state && $line === '') continue; |
|---|
| 77 | if ($line === '----') break; |
|---|
| 78 | if (strncmp('--', $line, 2) === 0) { |
|---|
| 79 | // Multiline declaration |
|---|
| 80 | $state = trim($line, '- '); |
|---|
| 81 | continue; |
|---|
| 82 | } elseif (!$state) { |
|---|
| 83 | $single = true; |
|---|
| 84 | if (strpos($line, ':') !== false) { |
|---|
| 85 | // Single-line declaration |
|---|
| 86 | list($state, $line) = explode(': ', $line, 2); |
|---|
| 87 | } else { |
|---|
| 88 | // Use default declaration |
|---|
| 89 | $state = $this->default; |
|---|
| 90 | } |
|---|
| 91 | } |
|---|
| 92 | if ($single) { |
|---|
| 93 | $ret[$state] = $line; |
|---|
| 94 | $single = false; |
|---|
| 95 | $state = false; |
|---|
| 96 | } else { |
|---|
| 97 | if (!isset($ret[$state])) $ret[$state] = ''; |
|---|
| 98 | $ret[$state] .= "$line\n"; |
|---|
| 99 | } |
|---|
| 100 | } while (!feof($fh)); |
|---|
| 101 | return $ret; |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | } |
|---|