data.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <?php
  2. /**
  3. * Implements data: URI for base64 encoded images supported by GD.
  4. */
  5. class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
  6. public $browsable = true;
  7. public $allowed_types = array(
  8. // you better write validation code for other types if you
  9. // decide to allow them
  10. 'image/jpeg' => true,
  11. 'image/gif' => true,
  12. 'image/png' => true,
  13. );
  14. public function validate(&$uri, $config, $context) {
  15. $result = explode(',', $uri->path, 2);
  16. $is_base64 = false;
  17. $charset = null;
  18. $content_type = null;
  19. if (count($result) == 2) {
  20. list($metadata, $data) = $result;
  21. // do some legwork on the metadata
  22. $metas = explode(';', $metadata);
  23. while(!empty($metas)) {
  24. $cur = array_shift($metas);
  25. if ($cur == 'base64') {
  26. $is_base64 = true;
  27. break;
  28. }
  29. if (substr($cur, 0, 8) == 'charset=') {
  30. // doesn't match if there are arbitrary spaces, but
  31. // whatever dude
  32. if ($charset !== null) continue; // garbage
  33. $charset = substr($cur, 8); // not used
  34. } else {
  35. if ($content_type !== null) continue; // garbage
  36. $content_type = $cur;
  37. }
  38. }
  39. } else {
  40. $data = $result[0];
  41. }
  42. if ($content_type !== null && empty($this->allowed_types[$content_type])) {
  43. return false;
  44. }
  45. if ($charset !== null) {
  46. // error; we don't allow plaintext stuff
  47. $charset = null;
  48. }
  49. $data = rawurldecode($data);
  50. if ($is_base64) {
  51. $raw_data = base64_decode($data);
  52. } else {
  53. $raw_data = $data;
  54. }
  55. // XXX probably want to refactor this into a general mechanism
  56. // for filtering arbitrary content types
  57. $file = tempnam("/tmp", "");
  58. file_put_contents($file, $raw_data);
  59. if (function_exists('exif_imagetype')) {
  60. $image_code = exif_imagetype($file);
  61. } elseif (function_exists('getimagesize')) {
  62. set_error_handler(array($this, 'muteErrorHandler'));
  63. $info = getimagesize($file);
  64. restore_error_handler();
  65. if ($info == false) return false;
  66. $image_code = $info[2];
  67. } else {
  68. trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR);
  69. }
  70. $real_content_type = image_type_to_mime_type($image_code);
  71. if ($real_content_type != $content_type) {
  72. // we're nice guys; if the content type is something else we
  73. // support, change it over
  74. if (empty($this->allowed_types[$real_content_type])) return false;
  75. $content_type = $real_content_type;
  76. }
  77. // ok, it's kosher, rewrite what we need
  78. $uri->userinfo = null;
  79. $uri->host = null;
  80. $uri->port = null;
  81. $uri->fragment = null;
  82. $uri->query = null;
  83. $uri->path = "$content_type;base64," . base64_encode($raw_data);
  84. return true;
  85. }
  86. public function muteErrorHandler($errno, $errstr) {}
  87. }