1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: if (!class_exists('File')) {
25: uses('object', 'file');
26: }
27: 28: 29: 30: 31: 32:
33: class MagicDb extends Object {
34: 35: 36: 37: 38:
39: var $db = array();
40:
41: 42: 43: 44: 45: 46: 47:
48: function read($magicDb = null) {
49: if (!is_string($magicDb) && !is_array($magicDb)) {
50: return false;
51: }
52: if (is_array($magicDb) || strpos($magicDb, '# FILE_ID DB') === 0) {
53: $data = $magicDb;
54: } else {
55: $File =& new File($magicDb);
56: if (!$File->exists()) {
57: return false;
58: }
59: if ($File->ext() == 'php') {
60: include($File->pwd());
61: $data = $magicDb;
62: } else {
63:
64: $data = $File->read();
65: }
66: }
67:
68: $magicDb = $this->toArray($data);
69: if (!$this->validates($magicDb)) {
70: return false;
71: }
72: return !!($this->db = $magicDb);
73: }
74:
75: 76: 77: 78: 79: 80: 81:
82: function toArray($data = null) {
83: if (is_array($data)) {
84: return $data;
85: }
86: if ($data === null) {
87: return $this->db;
88: }
89:
90: if (strpos($data, '# FILE_ID DB') !== 0) {
91: return array();
92: }
93:
94: $lines = explode("\r\n", $data);
95: $db = array();
96:
97: $validHeader = count($lines) > 3
98: && preg_match('/^# Date:([0-9]{4}-[0-9]{2}-[0-9]{2})$/', $lines[1], $date)
99: && preg_match('/^# Source:(.+)$/', $lines[2], $source)
100: && strlen($lines[3]) == 0;
101: if (!$validHeader) {
102: return $db;
103: }
104:
105: $db = array('header' => array('Date' => $date[1], 'Source' => $source[1]), 'database' => array());
106: $lines = array_splice($lines, 3);
107:
108: $format = array();
109: while (!empty($lines)) {
110: $line = array_shift($lines);
111: if (isset($line[0]) && $line[0] == '#' || empty($line)) {
112: continue;
113: }
114:
115: $columns = explode("\t", $line);
116: if (in_array($columns[0]{0}, array('>', '&'))) {
117: $format[] = $columns;
118: } elseif (!empty($format)) {
119: $db['database'][] = $format;
120: $format = array($columns);
121: } else {
122: $format = array($columns);
123: }
124: }
125:
126: return $db;
127: }
128:
129: 130: 131: 132: 133: 134: 135:
136: function validates($magicDb = null) {
137: if (is_null($magicDb)) {
138: $magicDb = $this->db;
139: } elseif (!is_array($magicDb)) {
140: $magicDb = $this->toArray($magicDb);
141: }
142:
143: return isset($magicDb['header'], $magicDb['database']) && is_array($magicDb['header']) && is_array($magicDb['database']);
144: }
145:
146: 147: 148: 149: 150: 151: 152: 153:
154: function analyze($file, $options = array()) {
155: if (!is_string($file)) {
156: return false;
157: }
158:
159: $matches = array();
160: $MagicFileResource =& new MagicFileResource($file);
161: foreach ($this->db['database'] as $format) {
162: $magic = $format[0];
163: $match = $MagicFileResource->test($magic);
164: if ($match === false) {
165: continue;
166: }
167: $matches[] = $magic;
168: }
169:
170: return $matches;
171: }
172: }
173:
174: 175: 176: 177: 178: 179:
180: class MagicFileResource extends Object{
181: 182: 183: 184: 185: 186:
187: var $resource = null;
188: 189: 190: 191: 192: 193:
194: var $offset = 0;
195: 196: 197: 198: 199: 200: 201:
202: function __construct($file) {
203: if (file_exists($file)) {
204: $this->resource =& new File($file);
205: } else {
206: $this->resource = $file;
207: }
208: }
209: 210: 211: 212: 213: 214: 215:
216: function test($magic) {
217: $offset = null;
218: $type = null;
219: $expected = null;
220: $comment = null;
221: if (isset($magic[0])) {
222: $offset = $magic[0];
223: }
224: if (isset($magic[1])) {
225: $type = $magic[1];
226: }
227: if (isset($magic[2])) {
228: $expected = $magic[2];
229: }
230: if (isset($magic[3])) {
231: $comment = $magic[3];
232: }
233: $val = $this->extract($offset, $type, $expected);
234: return $val == $expected;
235: }
236: 237: 238: 239: 240: 241: 242: 243:
244: function read($length = null) {
245: if (!is_object($this->resource)) {
246: return substr($this->resource, $this->offset, $length);
247: }
248: return $this->resource->read($length);
249: }
250: 251: 252: 253: 254: 255: 256: 257:
258: function extract($offset, $type, $expected) {
259: switch ($type) {
260: case 'string':
261: $this->offset($offset);
262: $val = $this->read(strlen($expected));
263: if ($val === $expected) {
264: return true;
265: }
266: break;
267: }
268: }
269: 270: 271: 272: 273: 274: 275: 276:
277: function offset($offset = null) {
278: if (is_null($offset)) {
279: if (!is_object($this->resource)) {
280: return $this->offset;
281: }
282: return $this->offset;
283: }
284:
285: if (!ctype_digit($offset)) {
286: return false;
287: }
288: if (is_object($this->resource)) {
289: $this->resource->offset($offset);
290: } else {
291: $this->offset = $offset;
292: }
293: }
294: }
295:
296: ?>