fork download
  1. <?php
  2. class MimeTypeDefinition {
  3. var $start;
  4. var $type;
  5. var $pattern;
  6. var $mime;
  7.  
  8. function __construct($start, $type, $pattern, $mime)
  9. {
  10. $this->start = $start;
  11. $this->type = $type;
  12. $this->pattern = $pattern;
  13. $this->mime = $mime;
  14. }
  15. }
  16. class MimeChecker {
  17. var $data = null;
  18. var $types = array();
  19.  
  20. function __construct()
  21. {
  22. }
  23.  
  24. function parse($filepath)
  25. {
  26. if((!file_exists($filepath)) || (is_dir($filepath)))
  27. {
  28. return "mimeタイプの定義ファイルが見つかりません。";
  29. }
  30.  
  31. $this->data = file($filepath);
  32.  
  33. $types = array(
  34. 'byte','short','long','string','date',
  35. 'beshort','belong','bedate',
  36. 'leshort','lelong','ledate'
  37. );
  38.  
  39. $ptn_types = implode('|', $types);
  40.  
  41. foreach($this->data as $line)
  42. {
  43. if(preg_match('/^#/', $line))
  44. {
  45. continue;
  46. }
  47.  
  48. '/^(>?\d+)\s+(' . $ptn_types . ')\s+((\x5c |[^\s])*)\s+([^\s]+)?/',
  49. $line, $match) == 0)
  50. {
  51. continue;
  52. }
  53. else
  54. {
  55. if(empty($match[5]))
  56. {
  57. $match[5] = null;
  58. }
  59.  
  60. $this->types[] = new MimeTypeDefinition($match[1], $match[2], $match[3], $match[5]);
  61. }
  62. }
  63.  
  64. return false;
  65. }
  66.  
  67. function getMime($path)
  68. {
  69. if(empty($this->data))
  70. {
  71. return false;
  72. }
  73.  
  74. if((!file_exists($path)) || (is_dir($path)))
  75. {
  76. return false;
  77. }
  78.  
  79. $mime = null;
  80. $fp = fopen($path, "rb");
  81.  
  82. $count = count($this->types);
  83.  
  84. for($i = 0; $i < $count;)
  85. {
  86. $start = $this->types[$i]->start;
  87.  
  88. if(preg_match('/^\d+$/', $start) > 0)
  89. {
  90. $mime = $this->checkMime($fp, $i);
  91. $i++;
  92.  
  93. if($mime)
  94. {
  95. return trim($mime);
  96. }
  97. }
  98. else
  99. {
  100. $i++;
  101. }
  102. }
  103.  
  104. if(!$mime)
  105. {
  106. return 'application/octet-stream';
  107. }
  108. }
  109.  
  110. function checkMime($fp, $i)
  111. {
  112. $ismatch = false;
  113.  
  114. switch($this->types[$i]->type)
  115. {
  116. case "byte" :
  117. $ismatch = $this->checkByte($fp, $this->types[$i]);
  118. break;
  119. case "short" :
  120. $ismatch = $this->checkShort($fp, $this->types[$i]);
  121. break;
  122. case "long" :
  123. $ismatch = $this->checkLong($fp, $this->types[$i]);
  124. break;
  125. case "string" :
  126. $ismatch = $this->checkStr($fp, $this->types[$i]);
  127. break;
  128. case "date" :
  129. $ismatch = $this->checkTime($fp, $this->types[$i]);
  130. break;
  131. case "beshort" :
  132. $ismatch = $this->checkBeShort($fp, $this->types[$i]);
  133. break;
  134. case "belong" :
  135. $ismatch = $this->checkBeLong($fp, $this->types[$i]);
  136. break;
  137. case "bedate" :
  138. $ismatch = $this->checkBeTime($fp, $this->types[$i]);
  139. break;
  140. case "leshort" :
  141. $ismatch = $this->checkLeShort($fp, $this->types[$i]);
  142. break;
  143. case "lelong" :
  144. $ismatch = $this->checkLeLong($fp, $this->types[$i]);
  145. break;
  146. case "ledate" :
  147. $ismatch = $this->checkLeTime($fp, $this->types[$i]);
  148. break;
  149. }
  150.  
  151. if((!$ismatch) && (preg_match('/^\d+$/', $this->types[$i]->start) > 0))
  152. {
  153. return null;
  154. }
  155.  
  156. if(isset($this->types[$i]->mime))
  157. {
  158. return $this->types[$i]->mime;
  159. }
  160.  
  161. $count = count($this->types);
  162.  
  163. for($i++; $i < $count; $i++)
  164. {
  165. if(preg_match('/^\d+$/', $this->types[$i]->start) > 0)
  166. {
  167. return null;
  168. }
  169. else
  170. {
  171. $mime = $this->checkMime($fp, $i);
  172.  
  173. if($mime)
  174. {
  175. return $mime;
  176. }
  177. }
  178. }
  179. }
  180.  
  181. function checkByte($fp, $type)
  182. {
  183. $start = $type->start;
  184.  
  185. if($type->pattern == "x")
  186. {
  187. return true;
  188. }
  189. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  190. {
  191. return false;
  192. }
  193.  
  194. if(empty($match[1]))
  195. {
  196. $match[1] = null;
  197. }
  198.  
  199. fseek($fp, $start);
  200. $data = fread($fp, 1);
  201.  
  202. return $this->checkInt($match[1], $match[2], $data);
  203.  
  204. }
  205.  
  206. function checkShort($fp, $type)
  207. {
  208. $start = $type->start;
  209.  
  210. if($type->pattern == "x")
  211. {
  212. return true;
  213. }
  214. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  215. {
  216. return false;
  217. }
  218.  
  219. if(empty($match[1]))
  220. {
  221. $match[1] = null;
  222. }
  223.  
  224. fseek($fp, $start);
  225. $data = fread($fp, 2);
  226.  
  227. return $this->checkInt($match[1], $match[2], $data);
  228.  
  229. }
  230.  
  231. function checkLong($fp, $type)
  232. {
  233. $start = $type->start;
  234.  
  235. if($type->pattern == "x")
  236. {
  237. return true;
  238. }
  239. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  240. {
  241. return false;
  242. }
  243.  
  244. if(empty($match[1]))
  245. {
  246. $match[1] = null;
  247. }
  248.  
  249. fseek($fp, $start);
  250. $data = fread($fp, 4);
  251.  
  252. return $this->checkInt($match[1], $match[2], $data);
  253.  
  254. }
  255.  
  256. function checkInt($mode, $num, $data, $packfmt = null)
  257. {
  258. if(preg_match('/^0x([\da-f]+)$/i', $num, $match) > 0)
  259. {
  260. $num = intval($match[1], 16);
  261. }
  262. else if(preg_match('/^0(\d+)$/', $num, $match) > 0)
  263. {
  264. $num = intval($match[1], 8);
  265. }
  266. else if(preg_match('/^(\d+)$/', $num, $match) > 0)
  267. {
  268. $num = intval($num, 10);
  269. }
  270. else
  271. {
  272. return false;
  273. }
  274.  
  275. if($packfmt)
  276. {
  277. switch($packfmt)
  278. {
  279. case "n" :
  280. break;
  281.  
  282. case "N" :
  283. break;
  284.  
  285. case "v" :
  286. break;
  287.  
  288. case "V" :
  289. break;
  290.  
  291. default:
  292. return false;
  293. }
  294.  
  295. $num = pack($packfmt, $num);
  296. }
  297.  
  298. if(empty($mode) || ($mode == "="))
  299. {
  300. if($data == $num)
  301. {
  302. return true;
  303. }
  304. }
  305. else if($mode == "<")
  306. {
  307. if($data < $num)
  308. {
  309. return true;
  310. }
  311. }
  312. else if($mode == ">")
  313. {
  314. if($data > $num)
  315. {
  316. return true;
  317. }
  318. }
  319. else if($mode == "&")
  320. {
  321. if(($data & $num) == $num)
  322. {
  323. return true;
  324. }
  325. }
  326. else if($mode == "^")
  327. {
  328. if(($data & $num) != $num)
  329. {
  330. return true;
  331. }
  332. }
  333. else if($mode == "~")
  334. {
  335. if($data == ~$num)
  336. {
  337. return true;
  338. }
  339. }
  340.  
  341. return false;
  342. }
  343.  
  344. function checkStr($fp, $type)
  345. {
  346. $start = $type->start;
  347.  
  348. if(preg_match('/^(=|<|>)?((\x5c |[^\s])*)$/i', $type->pattern, $match) == 0)
  349. {
  350. return false;
  351. }
  352.  
  353. if(empty($match[1]))
  354. {
  355. $match[1] = null;
  356. }
  357.  
  358. $match[2] = preg_replace('/\x5c /', ' ', $match[2]);
  359. $match[2] = preg_replace('/\x5c</', '<', $match[2]);
  360. $match[2] = preg_replace('/\x5c>/', '>', $match[2]);
  361. $match[2] = preg_replace('/\x5c=/', '=', $match[2]);
  362.  
  363. $ptn = $this->unescape($match[2]);
  364. $len = strlen($ptn);
  365.  
  366. fseek($fp, $start);
  367. $data = fread($fp, $len);
  368.  
  369. if(empty($match[1]) || ($match[1] == "="))
  370. {
  371. if(($match[0] == '=\0') && ($data == ""))
  372. {
  373. return true;
  374. }
  375. else if($data == $ptn)
  376. {
  377. return true;
  378. }
  379. else
  380. {
  381. return false;
  382. }
  383.  
  384. }
  385. else if($match[1] == "<")
  386. {
  387. if(strcmp($data, $ptn) < 0)
  388. {
  389. return true;
  390. }
  391. else
  392. {
  393. return false;
  394. }
  395. }
  396. else if($match[1] == ">")
  397. {
  398. if(($match[0] == '>\0') && ($data != ""))
  399. {
  400. return true;
  401. }
  402. else if(strcmp($data, $ptn) > 0)
  403. {
  404. return true;
  405. }
  406. else
  407. {
  408. return false;
  409. }
  410. }
  411. }
  412.  
  413. function checkTime($fp, $type)
  414. {
  415. $start = $type->start;
  416.  
  417. fseek($fp, $start);
  418. $data = fread($fp, 4);
  419.  
  420. if(intval($data) == intval($this->pattern))
  421. {
  422. return true;
  423. }
  424. else
  425. {
  426. return false;
  427. }
  428. }
  429.  
  430. function checkBeShort($fp, $type)
  431. {
  432. $start = $type->start;
  433.  
  434. if($type->pattern == "x")
  435. {
  436. return true;
  437. }
  438. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  439. {
  440. return false;
  441. }
  442.  
  443. if(empty($match[1]))
  444. {
  445. $match[1] = null;
  446. }
  447.  
  448. fseek($fp, $start);
  449. $data = fread($fp, 2);
  450.  
  451. return $this->checkInt($match[1], $match[2], $data, "n");
  452.  
  453. }
  454.  
  455. function checkBeLong($fp, $type)
  456. {
  457. $start = $type->start;
  458.  
  459. if($type->pattern == "x")
  460. {
  461. return true;
  462. }
  463. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  464. {
  465. return false;
  466. }
  467.  
  468. if(empty($match[1]))
  469. {
  470. $match[1] = null;
  471. }
  472.  
  473. fseek($fp, $start);
  474. $data = fread($fp, 4);
  475.  
  476. return $this->checkInt($match[1], $match[2], $data, "N");
  477.  
  478. }
  479.  
  480. function checkBeTime($fp, $type)
  481. {
  482. $start = $type->start;
  483.  
  484. fseek($fp, $start);
  485. $data = fread($fp, 4);
  486.  
  487. if(pack("N", intval($data)) == intval($this->pattern))
  488. {
  489. return true;
  490. }
  491. else
  492. {
  493. return false;
  494. }
  495. }
  496.  
  497. function checkLeShort($fp, $type)
  498. {
  499. $start = $type->start;
  500.  
  501. if($type->pattern == "x")
  502. {
  503. return true;
  504. }
  505. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  506. {
  507. return false;
  508. }
  509.  
  510. if(empty($match[1]))
  511. {
  512. $match[1] = null;
  513. }
  514.  
  515. fseek($fp, $start);
  516. $data = fread($fp, 2);
  517.  
  518. return $this->checkInt($match[1], $match[2], $data, "v");
  519.  
  520. }
  521.  
  522. function checkLeLong($fp, $type)
  523. {
  524. $start = $type->start;
  525.  
  526. if($type->pattern == "x")
  527. {
  528. return true;
  529. }
  530. else if(preg_match('/^(=|<|>|&|^|~)?(0?x?[\da-f]+)$/i', $type->pattern, $match) == 0)
  531. {
  532. return false;
  533. }
  534.  
  535. if(empty($match[1]))
  536. {
  537. $match[1] = null;
  538. }
  539.  
  540. fseek($fp, $start);
  541. $data = fread($fp, 4);
  542.  
  543. return $this->checkInt($match[1], $match[2], $data, "V");
  544.  
  545. }
  546.  
  547. function checkLeTime($fp, $type)
  548. {
  549. $start = $type->start;
  550.  
  551. fseek($fp, $start);
  552. $data = fread($fp, 4);
  553.  
  554. if(pack("V", intval($data)) == intval($this->pattern))
  555. {
  556. return true;
  557. }
  558. else
  559. {
  560. return false;
  561. }
  562. }
  563.  
  564. function unescape($str)
  565. {
  566. $ptn = array(
  567. '\d{3}', 'x[\da-f]{2}', '0', '01', '02', '03', '04', '05', '06',
  568. 'a', 'b', 't', 'n', 'v', 'f','r', '\x5c', '\x3f', '"', '\x27',
  569. );
  570. $ptn = implode('|', $ptn);
  571.  
  572. return preg_replace_callback('/\x5c(' . $ptn . ')/i', //'\\'と記述しても正常に動作しないため、\x5cと記述
  573. create_function('$match', 'return MimeChecker::unescapesub($match[1]);'),
  574. $str);
  575. }
  576.  
  577. static function unescapesub($match)
  578. {
  579. switch($match)
  580. {
  581. case "0" :
  582. return "\0";
  583. break;
  584. case "01" :
  585. return "\01";
  586. break;
  587. case "02" :
  588. return "\02";
  589. break;
  590. case "03" :
  591. return "\03";
  592. break;
  593. case "04" :
  594. return "\04";
  595. break;
  596. case "05" :
  597. return "\05";
  598. break;
  599. case "06" :
  600. return "\06";
  601. break;
  602. case "a" :
  603. return "\a";
  604. break;
  605. case "b" :
  606. return "\b";
  607. break;
  608. case "t" :
  609. return "\t";
  610. break;
  611. case "n" :
  612. return "\n";
  613. break;
  614. case "v" :
  615. return "\v";
  616. break;
  617. case "f" :
  618. return "\f";
  619. break;
  620. case "r" :
  621. return "\r";
  622. break;
  623. case "\x5c" :
  624. return "\x5c";
  625. break;
  626. case "?" :
  627. return "?";
  628. break;
  629. case "'" :
  630. return "'";
  631. break;
  632. case '"' :
  633. return '"';
  634. break;
  635. }
  636.  
  637. if(preg_match('/^(\d{3})$/', $match, $submatch) > 0)
  638. {
  639. return pack("C", intval($submatch[1], 8));
  640. }
  641. else if(preg_match('/^x([\da-f]{2})$/i', $match, $submatch) > 0)
  642. {
  643. return pack("C", intval($submatch[1], 16));
  644. }
  645. }
  646. }
  647. ?>
Success #stdin #stdout 0.02s 13112KB
stdin
Standard input is empty
stdout
Standard output is empty