Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.FileMimeConfig.php
Go to the documentation of this file.
1 <?php
2 namespace Dcp;
3 
4 class FileMimeConfig
5 {
6  //region Constants
7 
8  /**
9  * Default sys & user config file locations
10  */
11  const CONFIG_USER = 'config/file-mime-user.xml';
12  const CONFIG_SYS = 'config/file-mime.xml';
13  /**
14  * MIME type pattern specificity
15  */
16  const SPECIFICITY_ANY = 0; // Match any MIME type (pattern "*/*")
17  const SPECIFICITY_TYPE_ONLY = 1; // Match type (but not subtype) (pattern "xxx/*")
18  const SPECIFICITY_TYPE_AND_SUBTYPE = 2; // Match type and subtype (pattern "xxx/xxx")
19 
20  /**
21  * Targets: 'deny', 'allow'
22  */
23  const TARGET_DENY = 'deny';
24  const TARGET_ALLOW = 'allow';
25  //endregion
26  //region Properties
27 
28  /**
29  * @var array
30  */
31  protected $inlineRules = array(
32  '*/*' => self::TARGET_DENY
33  );
34  //endregion
35  //region public
36 
37  /**
38  * FileMime constructor.
39  * @param array $configFiles
40  */
41  public function __construct($configFiles = array())
42  {
43  if (count($configFiles) <= 0 || !is_array($configFiles)) {
44  $configFiles = array(
45  DEFAULT_PUBDIR . '/' . self::CONFIG_SYS,
46  DEFAULT_PUBDIR . '/' . self::CONFIG_USER
47  );
48  }
49  foreach ($configFiles as $configFile) {
50  $this->loadConfig($configFile);
51  }
52  }
53  /**
54  * @param string $mime
55  * @return bool
56  */
57  public static function isWellformedMIMEType($mime)
58  {
59  return (preg_match('!^[^ /]+/[^ /]+$!', $mime) === 1);
60  }
61  /**
62  * Match a MIME type (e.g. 'application/x-acme-file') to a MIME pattern (e.g. 'application/*')
63  *
64  * @param string $mime The MIME string to test
65  * @param string $pattern The MIME pattern with which the
66  * @return bool
67  */
68  public static function mimeMatch($mime, $pattern)
69  {
70  if (!self::isWellformedMIMEType($mime)) {
71  /* Invalid MIME type */
72  return false;
73  }
74  $patternSpecificity = self::getMimePatternSpecificity($pattern);
75  if ($patternSpecificity == self::SPECIFICITY_TYPE_AND_SUBTYPE) {
76  return ($mime === $pattern);
77  } elseif ($patternSpecificity == self::SPECIFICITY_TYPE_ONLY) {
78  $type_slash = substr($pattern, 0, -1); /* Keep the type with slash delimiter ('xxx/*' -> 'xxx/') for matching */
79  return (substr($mime, strlen($type_slash)) === $type_slash);
80  }
81  return true;
82  }
83  /**
84  * Check if a given MIME type is allowed
85  *
86  * @param string $mime The MIME type to check (e.g. 'application/x-acme-file')
87  * @return bool
88  */
89  public function isInlineAllowed($mime)
90  {
91  foreach ($this->inlineRules as $rulePattern => $ruleTarget) {
92  if ($this->mimeMatch($mime, $rulePattern)) {
93  return ($ruleTarget === self::TARGET_ALLOW);
94  }
95  }
96  return false;
97  }
98  //endregion
99  //region protected
100 
101  /**
102  * @param string $file
103  * @return bool
104  */
105  protected function loadConfig($file)
106  {
107  if (!is_scalar($file)) {
108  return false;
109  }
110  if (!file_exists($file)) {
111  return false;
112  }
113  if (($xml = simplexml_load_file($file)) === false) {
114  return false;
115  }
116  if (!isset($xml->inline)) {
117  return false;
118  }
119  $inlineRules = array();
120  /**
121  * @var \SimpleXMLElement $rule
122  */
123  foreach ($xml->inline->children() as $rule) {
124  $target = $rule->getName();
125  if ($target != self::TARGET_DENY && $target != self::TARGET_ALLOW) {
126  continue;
127  }
128  $attrs = $rule->attributes();
129  if (!isset($attrs['type'])) {
130  continue;
131  }
132  $type = (string)$attrs['type'];
133  $inlineRules[$type] = $target;
134  }
135  return $this->mergeInlineRules($inlineRules);
136  }
137  /**
138  * @param array $rules
139  * @return bool
140  */
141  protected function mergeInlineRules($rules)
142  {
143  foreach ($rules as $mime => $target) {
144  $this->inlineRules[$mime] = $target;
145  }
146  /* Order rules with most specificity first and least specificity last */
147  uksort($this->inlineRules, function ($mime1, $mime2)
148  {
149  return $this->cmpMimePatternSpecificity($mime2, $mime1);
150  });
151  return true;
152  }
153  /**
154  * Compare MIME patterns by ascending specificity (from least specific to most specific)
155  *
156  * @param string $mime1
157  * @param string $mime2
158  * @return int
159  */
160  protected function cmpMimePatternSpecificity($mime1, $mime2)
161  {
162  if (($cmp = (self::getMimePatternSpecificity($mime1) - self::getMimePatternSpecificity($mime2))) === 0) {
163  return strcmp($mime1, $mime2);
164  }
165  return $cmp;
166  }
167  /**
168  * Get the specificity of a MIME pattern
169  * @param string $pattern
170  * @return int Specificity of MIME type: 0 (least specific), 1, or 2 (most specific)
171  */
172  protected static function getMimePatternSpecificity($pattern)
173  {
174  $specificity = self::SPECIFICITY_TYPE_AND_SUBTYPE;
175  if ($pattern === '*/*') {
176  $specificity = self::SPECIFICITY_ANY;
177  } elseif (substr($pattern, -2) === '/*') {
178  $specificity = self::SPECIFICITY_TYPE_ONLY;
179  }
180  return $specificity;
181  }
182  //endregion
183 
184 }
$file
const DEFAULT_PUBDIR
Definition: Lib.Prefix.php:28
← centre documentaire © anakeen