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: 25:
26:
27:
28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49:
50: class Mage_Core_Model_File_Validator_AvailablePath extends Zend_Validate_Abstract
51: {
52: const PROTECTED_PATH = 'protectedPath';
53: const NOT_AVAILABLE_PATH = 'notAvailablePath';
54: const PROTECTED_LFI = 'protectedLfi';
55:
56: 57: 58: 59: 60:
61: protected $_value;
62:
63: 64: 65: 66: 67:
68: protected $_protectedPaths = array();
69:
70: 71: 72: 73: 74:
75: protected $_availablePaths = array();
76:
77: 78: 79: 80: 81:
82: protected $_pathsData;
83:
84: 85: 86:
87: public function __construct()
88: {
89: $this->_initMessageTemplates();
90: }
91:
92: 93: 94: 95: 96:
97: protected function _initMessageTemplates()
98: {
99: if (!$this->_messageTemplates) {
100: $this->_messageTemplates = array(
101: self::PROTECTED_PATH =>
102: Mage::helper('core')->__('Path "%value%" is protected and cannot be used.'),
103: self::NOT_AVAILABLE_PATH =>
104: Mage::helper('core')->__('Path "%value%" is not available and cannot be used.'),
105: self::PROTECTED_LFI =>
106: Mage::helper('core')->__('Path "%value%" may not include parent directory traversal ("../", "..\\").'),
107: );
108: }
109: return $this;
110: }
111:
112: 113: 114: 115: 116: 117: 118:
119: public function setPaths(array $paths)
120: {
121: if (isset($paths['available']) && is_array($paths['available'])) {
122: $this->_availablePaths = $paths['available'];
123: }
124: if (isset($paths['protected']) && is_array($paths['protected'])) {
125: $this->_protectedPaths = $paths['protected'];
126: }
127: return $this;
128: }
129:
130: 131: 132: 133: 134: 135:
136: public function setProtectedPaths(array $paths)
137: {
138: $this->_protectedPaths = $paths;
139: return $this;
140: }
141:
142: 143: 144: 145: 146: 147:
148: public function addProtectedPath($path)
149: {
150: if (is_array($path)) {
151: $this->_protectedPaths = array_merge($this->_protectedPaths, $path);
152: } else {
153: $this->_protectedPaths[] = $path;
154: }
155: return $this;
156: }
157:
158: 159: 160: 161: 162:
163: public function getProtectedPaths()
164: {
165: return $this->_protectedPaths;
166: }
167:
168: 169: 170: 171: 172: 173:
174: public function setAvailablePaths(array $paths)
175: {
176: $this->_availablePaths = $paths;
177: return $this;
178: }
179:
180: 181: 182: 183: 184: 185:
186: public function addAvailablePath($path)
187: {
188: if (is_array($path)) {
189: $this->_availablePaths = array_merge($this->_availablePaths, $path);
190: } else {
191: $this->_availablePaths[] = $path;
192: }
193: return $this;
194: }
195:
196: 197: 198: 199: 200:
201: public function getAvailablePaths()
202: {
203: return $this->_availablePaths;
204: }
205:
206:
207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217:
218: public function isValid($value)
219: {
220: $value = trim($value);
221: $this->_setValue($value);
222:
223: if (!$this->_availablePaths && !$this->_protectedPaths) {
224: throw new Exception(Mage::helper('core')->__('Please set available and/or protected paths list(s) before validation.'));
225: }
226:
227: if (preg_match('#\.\.[\\\/]#', $this->_value)) {
228: $this->_error(self::PROTECTED_LFI, $this->_value);
229: return false;
230: }
231:
232:
233: $value = str_replace(array('/', '\\'), DS, $this->_value);
234: $valuePathInfo = pathinfo(ltrim($value, '\\/'));
235: if ($valuePathInfo['dirname'] == '.' || $valuePathInfo['dirname'] == DS) {
236: $valuePathInfo['dirname'] = '';
237: }
238:
239: if ($this->_protectedPaths && !$this->_isValidByPaths($valuePathInfo, $this->_protectedPaths, true)) {
240: $this->_error(self::PROTECTED_PATH, $this->_value);
241: return false;
242: }
243: if ($this->_availablePaths && !$this->_isValidByPaths($valuePathInfo, $this->_availablePaths, false)) {
244: $this->_error(self::NOT_AVAILABLE_PATH, $this->_value);
245: return false;
246: }
247:
248: return true;
249: }
250:
251: 252: 253: 254: 255: 256: 257: 258:
259: protected function _isValidByPaths($valuePathInfo, $paths, $protected)
260: {
261: foreach ($paths as $path) {
262: $path = ltrim($path, '\\/');
263: if (!isset($this->_pathsData[$path]['regFilename'])) {
264: $pathInfo = pathinfo($path);
265: $options['file_mask'] = $pathInfo['basename'];
266: if ($pathInfo['dirname'] == '.' || $pathInfo['dirname'] == DS) {
267: $pathInfo['dirname'] = '';
268: } else {
269: $pathInfo['dirname'] = str_replace(array('/', '\\'), DS, $pathInfo['dirname']);
270: }
271: $options['dir_mask'] = $pathInfo['dirname'];
272: $this->_pathsData[$path]['options'] = $options;
273: } else {
274: $options = $this->_pathsData[$path]['options'];
275: }
276:
277:
278: if (false !== (strpos($options['file_mask'], '*'))) {
279: if (!isset($this->_pathsData[$path]['regFilename'])) {
280:
281: $reg = $options['file_mask'];
282: $reg = str_replace('.', '\.', $reg);
283: $reg = str_replace('*', '.*?', $reg);
284: $reg = "/^($reg)$/";
285: } else {
286: $reg = $this->_pathsData[$path]['regFilename'];
287: }
288: $resultFile = preg_match($reg, $valuePathInfo['basename']);
289: } else {
290: $resultFile = ($options['file_mask'] == $valuePathInfo['basename']);
291: }
292:
293:
294: $reg = $options['dir_mask'] . DS;
295: if (!isset($this->_pathsData[$path]['regDir'])) {
296:
297: $reg = str_replace('.', '\.', $reg);
298: $reg = str_replace('*\\', '||', $reg);
299: $reg = str_replace('*/', '||', $reg);
300:
301: $reg = str_replace(DS, '[\\' . DS . ']', $reg);
302: $reg = str_replace('?', '([^\\' . DS . ']+)', $reg);
303: $reg = str_replace('||', '(.*[\\' . DS . '])?', $reg);
304: $reg = "/^$reg$/";
305: } else {
306: $reg = $this->_pathsData[$path]['regDir'];
307: }
308: $resultDir = preg_match($reg, $valuePathInfo['dirname'] . DS);
309:
310: if ($protected && ($resultDir && $resultFile)) {
311: return false;
312: } elseif (!$protected && ($resultDir && $resultFile)) {
313:
314: return true;
315: }
316: }
317: if ($protected) {
318: return true;
319: } else {
320:
321: return false;
322: }
323: }
324: }
325: