File indexing completed on 2024-11-24 05:19:04

0001 <?php
0002 /**
0003  * Image media server - part of Opendesktop.org platform project <https://www.opendesktop.org>.
0004  *
0005  * Copyright (c) 2016 pling GmbH.
0006  *
0007  * This program is free software: you can redistribute it and/or modify
0008  * it under the terms of the GNU Affero General Public License as
0009  * published by the Free Software Foundation, either version 3 of the
0010  * License, or (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU Affero General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Affero General Public License
0018  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0019  */
0020 
0021 namespace Ocs\Filter\File;
0022 
0023 use Laminas\Filter\AbstractFilter;
0024 
0025 class Filename extends AbstractFilter
0026 {
0027     protected $beautify;
0028 
0029     public function __construct($options = [])
0030     {
0031         $this->beautify = true;
0032         if (isset($options['beautify'])) {
0033             $this->beautify = $options['beautify'];
0034         }
0035 
0036     }
0037 
0038     /**
0039      * @inheritDoc
0040      */
0041     public function filter($value)
0042     {
0043         if (is_string($value)) {
0044             return $this->filter_filename($value);
0045         }
0046 
0047         if (false == isset($value['name'])) {
0048             return $value;
0049         }
0050 
0051         $value['name'] = $this->filter_filename($value['name']);
0052 
0053         return $value;
0054     }
0055 
0056     /**
0057      * @param string $filename
0058      *
0059      * @return string
0060      */
0061     private function filter_filename(string $filename): string
0062     {
0063         // try to prevent filesystem traversal attacks
0064         $filename = basename($filename);
0065         // sanitize filename
0066         $filename = preg_replace('~
0067         [<>:"/\\|?*]|            # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
0068         [\x00-\x1F]|             # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
0069         [\x7F\xA0\xAD]|          # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
0070         [#\[\]@!$&\'()+,;=]|     # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
0071         [{}^\~`]                 # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
0072         ~x', '-', $filename);
0073         // avoids ".", ".." or ".hiddenFiles"
0074         $filename = ltrim($filename, '.-');
0075         // optional beautification
0076         if ($this->beautify) {
0077             $filename = $this->beautify_filename($filename);
0078         }
0079         // maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
0080         $ext = pathinfo($filename, PATHINFO_EXTENSION);
0081         $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : '');
0082 
0083         return $filename;
0084     }
0085 
0086     /**
0087      * @param string $filename
0088      *
0089      * @return string
0090      */
0091     private function beautify_filename($filename): string
0092     {
0093         // reduce consecutive characters
0094         $filename = preg_replace(array(// "file   name.zip" becomes "file-name.zip"
0095                                        '/ +/',
0096                                        // "file___name.zip" becomes "file-name.zip"
0097                                        '/_+/',
0098                                        // "file---name.zip" becomes "file-name.zip"
0099                                        '/-+/'), '-', $filename);
0100         $filename = preg_replace(array(// "file--.--.-.--name.zip" becomes "file.name.zip"
0101                                        '/-*\.-*/',
0102                                        // "file...name..zip" becomes "file.name.zip"
0103                                        '/\.{2,}/'), '.', $filename);
0104         // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625
0105         //$filename = mb_strtolower($filename, mb_detect_encoding($filename));
0106         // ".file-name.-" becomes "file-name"
0107         $filename = trim($filename, '.-');
0108 
0109         return $filename;
0110     }
0111 
0112     /**
0113      * @return mixed
0114      */
0115     public function getBeautify()
0116     {
0117         return $this->beautify;
0118     }
0119 
0120     /**
0121      * @param mixed $beautify
0122      */
0123     public function setBeautify($beautify): void
0124     {
0125         $this->beautify = $beautify;
0126     }
0127 
0128 }