source: trunk/lib/Upload.inc.php @ 301

Last change on this file since 301 was 301, checked in by quinn, 16 years ago

Added minor functinoality to Upload. Fixed (?) XML serialier config in PEdit.

File size: 29.9 KB
Line 
1<?php
2/**
3 * Upload.inc.php
4 * Code by Strangecode :: www.strangecode.com :: This document contains copyrighted information
5 *
6 * The Upload class provides an interface to deal with http uploaded files.
7 *
8 * @author  Quinn Comendant <quinn@strangecode.com>
9 * @requires App.inc.php
10 * @version 1.4
11 */
12
13// Upload error types.
14define('UPLOAD_USER_ERR_EMPTY_FILE', 100);
15define('UPLOAD_USER_ERR_NOT_UPLOADED_FILE', 101);
16define('UPLOAD_USER_ERR_INVALID_EXTENSION', 102);
17define('UPLOAD_USER_ERR_NOT_UNIQUE', 103);
18define('UPLOAD_USER_ERR_MOVE_FAILED', 104);
19
20class Upload {
21
22    // General object parameters.
23    var $_params = array(
24
25        // Which messages do we pass to raiseMsg?
26        'display_messages' => MSG_ALL,
27
28        // Existing files will be overwritten when there is a name conflict?
29        'allow_overwriting' => false,
30
31        // The filesystem path to the final upload directory.
32        'upload_path' => null,
33
34        // The file permissions of the uploaded files. Remember, files will be owned by the web server user.
35        'dest_file_perms' => 0600,
36
37        // The file permissions of the uploaded files. Remember, files will be owned by the web server user.
38        'dest_dir_perms' => 0700,
39
40        // Require file to have one of the following file name extentions.
41        'valid_file_extensions' => array('jpg', 'jpeg', 'gif', 'png', 'pdf', 'txt', 'text', 'html', 'htm'),
42    );
43
44    // Array of files with errors.
45    var $errors = array();
46
47    // Array of file name extensions and corresponding mime-types.
48    var $mime_extension_map = array( 'ez' => 'application/andrew-inset', 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', 'doc' => 'application/msword', 'bin' => 'application/octet-stream', 'class' => 'application/octet-stream', 'dll' => 'application/octet-stream', 'dms' => 'application/octet-stream', 'exe' => 'application/octet-stream', 'lha' => 'application/octet-stream', 'lzh' => 'application/octet-stream', 'so' => 'application/octet-stream', 'oda' => 'application/oda', 'pdf' => 'application/pdf', 'ai' => 'application/postscript', 'eps' => 'application/postscript', 'ps' => 'application/postscript', 'smi' => 'application/smil', 'smil' => 'application/smil', 'mif' => 'application/vnd.mif', 'xls' => 'application/vnd.ms-excel', 'ppt' => 'application/vnd.ms-powerpoint', 'sxc' => 'application/vnd.sun.xml.calc', 'stc' => 'application/vnd.sun.xml.calc.template', 'sxd' => 'application/vnd.sun.xml.draw', 'std' => 'application/vnd.sun.xml.draw.template', 'sxi' => 'application/vnd.sun.xml.impress', 'sti' => 'application/vnd.sun.xml.impress.template', 'sxm' => 'application/vnd.sun.xml.math', 'sxw' => 'application/vnd.sun.xml.writer', 'sxg' => 'application/vnd.sun.xml.writer.global', 'stw' => 'application/vnd.sun.xml.writer.template', 'vsd' => 'application/vnd.visio', 'wbxml' => 'application/vnd.wap.wbxml', 'wmlc' => 'application/vnd.wap.wmlc', 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'bcpio' => 'application/x-bcpio', 'vcd' => 'application/x-cdlink', 'pgn' => 'application/x-chess-pgn', 'Z' => 'application/x-compress', 'cpio' => 'application/x-cpio', 'csh' => 'application/x-csh', 'dcr' => 'application/x-director', 'dir' => 'application/x-director', 'dxr' => 'application/x-director', 'dvi' => 'application/x-dvi', 'spl' => 'application/x-futuresplash', 'gtar' => 'application/x-gtar', 'tgz' => 'application/x-gtar', 'gz' => 'application/x-gzip', 'hdf' => 'application/x-hdf', 'php' => 'application/x-httpd-php', 'php3' => 'application/x-httpd-php3', 'js' => 'application/x-javascript', 'skd' => 'application/x-koan', 'skm' => 'application/x-koan', 'skp' => 'application/x-koan', 'skt' => 'application/x-koan', 'latex' => 'application/x-latex', 'wmd' => 'application/x-ms-wmd', 'wmz' => 'application/x-ms-wmz', 'cdf' => 'application/x-netcdf', 'nc' => 'application/x-netcdf', 'pl' => 'application/x-perl', 'pm' => 'application/x-perl', 'psd' => 'application/x-photoshop', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', 'swf' => 'application/x-shockwave-flash', 'sit' => 'application/x-stuffit', 'sv4cpio' => 'application/x-sv4cpio', 'sv4crc' => 'application/x-sv4crc', 'tar' => 'application/x-tar', 'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', 'roff' => 'application/x-troff', 't' => 'application/x-troff', 'tr' => 'application/x-troff', 'man' => 'application/x-troff-man', 'me' => 'application/x-troff-me', 'ms' => 'application/x-troff-ms', 'ustar' => 'application/x-ustar', 'src' => 'application/x-wais-source', 'xht' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml', 'xml' => 'application/xml', 'zip' => 'application/zip', 'au' => 'audio/basic', 'snd' => 'audio/basic', 'kar' => 'audio/midi', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mp2' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mpga' => 'audio/mpeg', 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'm3u' => 'audio/x-mpegurl', 'wax' => 'audio/x-ms-wax', 'wma' => 'audio/x-ms-wma', 'ram' => 'audio/x-pn-realaudio', 'rm' => 'audio/x-pn-realaudio', 'rpm' => 'audio/x-pn-realaudio-plugin', 'ra' => 'audio/x-realaudio', 'wav' => 'audio/x-wav', 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-xyz', 'bmp' => 'image/bmp', 'gif' => 'image/gif', 'ief' => 'image/ief', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'png' => 'image/png', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'wbmp' => 'image/vnd.wap.wbmp', 'ras' => 'image/x-cmu-raster', 'pnm' => 'image/x-portable-anymap', 'pbm' => 'image/x-portable-bitmap', 'pgm' => 'image/x-portable-graymap', 'ppm' => 'image/x-portable-pixmap', 'rgb' => 'image/x-rgb', 'xbm' => 'image/x-xbitmap', 'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', 'iges' => 'model/iges', 'igs' => 'model/iges', 'mesh' => 'model/mesh', 'msh' => 'model/mesh', 'silo' => 'model/mesh', 'vrml' => 'model/vrml', 'wrl' => 'model/vrml', 'ics' => 'text/calendar', 'ifb' => 'text/calendar', 'vcs' => 'text/calendar', 'vfb' => 'text/calendar', 'css' => 'text/css', 'csv' => 'text/csv', 'diff' => 'text/diff', 'patch' => 'text/diff', 'htm' => 'text/html', 'html' => 'text/html', 'shtml' => 'text/html', 'asc' => 'text/plain', 'log' => 'text/plain', 'po' => 'text/plain', 'txt' => 'text/plain', 'rtx' => 'text/richtext', 'rtf' => 'text/rtf', 'sgm' => 'text/sgml', 'sgml' => 'text/sgml', 'tsv' => 'text/tab-separated-values', 'wml' => 'text/vnd.wap.wml', 'wmls' => 'text/vnd.wap.wmlscript', 'etx' => 'text/x-setext', 'vcf' => 'text/x-vcard', 'xsl' => 'text/xml', 'mp4' => 'video/mp4', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mov' => 'video/quicktime', 'qt' => 'video/quicktime', 'mxu' => 'video/vnd.mpegurl', 'asf' => 'video/x-ms-asf', 'asx' => 'video/x-ms-asf', 'wm' => 'video/x-ms-wm', 'wmv' => 'video/x-ms-wmv', 'wmx' => 'video/x-ms-wmx', 'wvx' => 'video/x-ms-wvx', 'avi' => 'video/x-msvideo', 'movie' => 'video/x-sgi-movie', 'ice' => 'x-conference/x-cooltalk', );
49
50    /**
51     * Set (or overwrite existing) parameters by passing an array of new parameters.
52     *
53     * @access public
54     * @param  array    $params     Array of parameters (key => val pairs).
55     */
56    function setParam($params)
57    {
58        $app =& App::getInstance();
59
60        if (isset($params) && is_array($params)) {
61
62            // Enforce valid upload_path parameter.
63            if (isset($params['upload_path'])) {
64                $params['upload_path'] = realpath($params['upload_path']);
65                // Source must be directory.
66                if (!is_dir($params['upload_path'])) {
67                    $app->logMsg(sprintf('Attempting to auto-create upload directory: %s', $params['upload_path']), LOG_NOTICE, __FILE__, __LINE__);
68                    if (phpversion() > '5') {
69                        // Recursive.
70                        mkdir($params['upload_path'], isset($params['dest_dir_perms']) ? $params['dest_dir_perms'] : $this->getParam('dest_dir_perms'), true);
71                    } else {
72                        mkdir($params['upload_path'], isset($params['dest_dir_perms']) ? $params['dest_dir_perms'] : $this->getParam('dest_dir_perms'));
73                    }
74                    if (!is_dir($params['upload_path'])) {
75                        $app->logMsg(sprintf('Upload directory invalid: %s', $params['upload_path']), LOG_ERR, __FILE__, __LINE__);
76                        trigger_error(sprintf('Upload directory invalid: %s', $params['upload_path']), E_USER_ERROR);
77                    }
78                }
79                // Source must be writable.
80                if (!is_writable($params['upload_path'])) {
81                    $app->logMsg(sprintf('Upload directory not writable: %s', $params['upload_path']), LOG_ERR, __FILE__, __LINE__);
82                    trigger_error(sprintf('Upload directory not writable: %s', $params['upload_path']), E_USER_ERROR);
83                }
84            }
85
86            // Merge new parameters with old overriding only those passed.
87            $this->_params = array_merge($this->_params, $params);
88        } else {
89            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
90        }
91    }
92
93    /**
94     * Return the value of a parameter, if it exists.
95     *
96     * @access public
97     * @param string $param        Which parameter to return.
98     * @return mixed               Configured parameter value.
99     */
100    function getParam($param)
101    {
102        $app =& App::getInstance();
103   
104        if (isset($this->_params[$param])) {
105            return $this->_params[$param];
106        } else {
107            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
108            return null;
109        }
110    }
111
112    /**
113     * Process uploaded files. Processes files existing within the specified $_FILES['form_name'] array.
114     * It tests for errors, cleans the filename, optionally sets custom file names. It will process
115     * multiple files automatically if the file form element is an array (<input type="file" name="myfiles[]" />).
116     *
117     * @access  public
118     * @param   string  $form_name          The name of the form to process.
119     * @param   string  $custom_file_name   The new name of the file. An array of filenames in the case of multiple files.
120     * @return  mixed   Returns FALSE if a major error occured preventing any file uploads.
121     *                  Returns an empty array if any minor errors occured or no files were found.
122     *                  Returns a multidimentional array of filenames, sizes and extentions, if one-or-more files succeeded uploading.
123     *                  Note: this last option presents a problem in the case of when some files uploaded successfully, and some failed.
124     *                        In this case it is necessary to check the Upload::anyErrors method to discover if any did fail.
125     */
126    function process($form_name, $custom_file_name=null)
127    {
128        $app =& App::getInstance();
129
130        // Ensure we have a upload directory.
131        if (!$this->getParam('upload_path')) {
132            $app->logMsg(sprintf('Upload directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
133            $this->_raiseMsg(_("There was a problem with the file upload. Please try again later."), MSG_ERR, __FILE__, __LINE__);
134            return false;
135        }
136
137        // Ensure the file form element specified actually exists.
138        if (!isset($_FILES[$form_name])) {
139            $app->logMsg(sprintf('Form element %s does not exist.', $form_name), LOG_ERR, __FILE__, __LINE__);
140            $this->_raiseMsg(_("There was a problem with the file upload. Please try again later."), MSG_ERR, __FILE__, __LINE__);
141            return false;
142        }
143
144        if (is_array($_FILES[$form_name]['name'])) {
145            $files = $_FILES[$form_name];
146        } else {
147            // Convert variables to single-cell array so it will loop.
148            $files = array(
149                'name'      => array($_FILES[$form_name]['name']),
150                'type'      => array($_FILES[$form_name]['type']),
151                'tmp_name'  => array($_FILES[$form_name]['tmp_name']),
152                'error'     => array($_FILES[$form_name]['error']),
153                'size'      => array($_FILES[$form_name]['size']),
154            );
155        }
156
157        // To keep this script running even if user tries to stop browser.
158        ignore_user_abort(true);
159        ini_set('max_execution_time', 300);
160        ini_set('max_input_time', 300);
161
162        $new_file_names = array();
163
164        $num = sizeof($files['name']);
165        for ($i=0; $i<$num; $i++) {
166            $file_path_name = '';
167
168            if ('' == trim($files['name'][$i])) {
169                // User may not have attached a file.
170                continue;
171            }
172
173            // Determine final file name.
174            if ($num == 1) {
175                // Single upload.
176                if (isset($custom_file_name)) {
177                    if (is_array($custom_file_name) && sizeof($custom_file_name) == 1) {
178                        // Is an array, but just one value. Pull it out.
179                        $custom_file_name = current($custom_file_name);
180                        $this->_raiseMsg(sprintf(_("The file %s has been renamed to %s."), $files['name'][$i], $file_name), MSG_NOTICE, __FILE__, __LINE__);
181                        $app->logMsg(sprintf('Using custom file name: %s', $file_name), LOG_DEBUG, __FILE__, __LINE__);
182                    } else if (!is_array($custom_file_name) && '' != $custom_file_name) {
183                        // Valid custom file name.
184                        $file_name = $custom_file_name;
185                        $this->_raiseMsg(sprintf(_("The file %s has been renamed to %s."), $files['name'][$i], $file_name), MSG_NOTICE, __FILE__, __LINE__);
186                        $app->logMsg(sprintf('Using custom file name: %s', $file_name), LOG_DEBUG, __FILE__, __LINE__);
187                    } else {
188                        // Invalid custom file name provided. Use uploaded file name.
189                        $file_name = $files['name'][$i];
190                        $app->logMsg(sprintf('Custom filename invalid! Using uploaded file name: %s', $file_name), LOG_WARNING, __FILE__, __LINE__);
191                    }
192                } else {
193                    // Normal case. Use uploaded file name.
194                    $file_name = $files['name'][$i];
195                    $app->logMsg(sprintf('Using uploaded file name: %s', $file_name), LOG_DEBUG, __FILE__, __LINE__);
196                }
197            } else {
198                // Multiple upload. Final file names must be array.
199                if (isset($custom_file_name) && is_array($custom_file_name) && '' != $custom_file_name[$i]) {
200                    // Valid custom file name.
201                    $file_name = $custom_file_name[$i];
202                    $this->_raiseMsg(sprintf(_("The file %s has been renamed to %s."), $files['name'][$i], $file_name), MSG_NOTICE, __FILE__, __LINE__);
203                    $app->logMsg(sprintf('Using custom file name: %s', $file_name), LOG_DEBUG, __FILE__, __LINE__);
204                } else {
205                    // Invalid custom file name provided. Use uploaded file name.
206                    $file_name = $files['name'][$i];
207                    $app->logMsg(sprintf('Using uploaded file name: %s', $file_name), LOG_DEBUG, __FILE__, __LINE__);
208                }
209            }
210
211            // Check The php upload error messages.
212            if (UPLOAD_ERR_INI_SIZE === $files['error'][$i]) { // Error code 1
213                $this->_raiseMsg(sprintf(_("The file %s failed uploading: it exceeds the maximum allowed upload file size of %s."), $file_name, ini_get('upload_max_filesize')), MSG_ERR, __FILE__, __LINE__);
214                $app->logMsg(sprintf('The file %s failed uploading with PHP error UPLOAD_ERR_INI_SIZE (currently %s).', $file_name, ini_get('upload_max_filesize')), LOG_ERR, __FILE__, __LINE__);
215                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_ERR_INI_SIZE);
216                continue;
217            }
218            if (UPLOAD_ERR_FORM_SIZE === $files['error'][$i]) { // Error code 2
219                $this->_raiseMsg(sprintf(_("The file %s failed uploading: it exceeds the maximum allowed upload file size of %s."), $file_name, $_POST['MAX_FILE_SIZE']), MSG_ERR, __FILE__, __LINE__);
220                $app->logMsg(sprintf('The file %s failed uploading with PHP error UPLOAD_ERR_FORM_SIZE (currently %s).', $file_name, $_POST['MAX_FILE_SIZE']), LOG_ERR, __FILE__, __LINE__);
221                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_ERR_FORM_SIZE);
222                continue;
223            }
224            if (UPLOAD_ERR_PARTIAL === $files['error'][$i]) { // Error code 3
225                $this->_raiseMsg(sprintf(_("The file %s failed uploading: it was only partially uploaded."), $file_name), MSG_ERR, __FILE__, __LINE__);
226                $app->logMsg(sprintf('The file %s failed uploading with PHP error UPLOAD_ERR_PARTIAL.', $file_name), LOG_ERR, __FILE__, __LINE__);
227                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_ERR_PARTIAL);
228                continue;
229            }
230            if (UPLOAD_ERR_NO_FILE === $files['error'][$i]) { // Error code 4
231                $this->_raiseMsg(sprintf(_("The file %s failed uploading: no file was uploaded."), $file_name), MSG_ERR, __FILE__, __LINE__);
232                $app->logMsg(sprintf('The file %s failed uploading with PHP error UPLOAD_ERR_NO_FILE.', $file_name), LOG_ERR, __FILE__, __LINE__);
233                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_ERR_NO_FILE);
234                continue;
235            }
236            if (UPLOAD_ERR_NO_TMP_DIR === $files['error'][$i]) { // Error code 6
237                $this->_raiseMsg(sprintf(_("The file %s failed uploading: temporary upload directory missing."), $file_name), MSG_ERR, __FILE__, __LINE__);
238                $app->logMsg(sprintf('The file %s failed uploading with PHP error UPLOAD_ERR_NO_TMP_DIR.', $file_name), LOG_ERR, __FILE__, __LINE__);
239                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_ERR_NO_TMP_DIR);
240                continue;
241            }
242
243            // Check to be sure it's an uploaded file.
244            if (!is_uploaded_file($files['tmp_name'][$i])) {
245                $this->_raiseMsg(sprintf(_("The file %s failed uploading."), $file_name), MSG_ERR, __FILE__, __LINE__);
246                $app->logMsg(sprintf('The file %s failed is_uploaded_file.', $file_name), LOG_ERR, __FILE__, __LINE__);
247                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_USER_ERR_NOT_UPLOADED_FILE);
248                continue;
249            }
250
251            // Check to be sure the file is not empty.
252            if ($files['size'][$i] <= 0) {
253                $this->_raiseMsg(sprintf(_("The file %s failed uploading: it contains zero bytes."), $file_name), MSG_ERR, __FILE__, __LINE__);
254                $app->logMsg(sprintf('The uploaded file %s contains zero bytes.', $file_name), LOG_ERR, __FILE__, __LINE__);
255                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_USER_ERR_EMPTY_FILE);
256                continue;
257            }
258
259            // Check to be sure the file has a valid file name extension.
260            if (!in_array(mb_strtolower($this->getFilenameExtension($file_name)), $this->getParam('valid_file_extensions'))) {
261                $this->_raiseMsg(sprintf(_("The file %s failed uploading: it is an unrecognized type. Files must have one of the following file name extensions: %s."), $file_name, join(', ', $this->getParam('valid_file_extensions'))), MSG_ERR, __FILE__, __LINE__);
262                $app->logMsg(sprintf('The uploaded file %s has an unrecognized file name extension.', $file_name), LOG_WARNING, __FILE__, __LINE__);
263                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_USER_ERR_INVALID_EXTENSION);
264                continue;
265            }
266
267            // Check to be sure the file has a unique file name.
268            if (!$this->getParam('allow_overwriting') && $this->exists($file_name)) {
269                $this->_raiseMsg(sprintf(_("The file %s failed uploading: a file with that name already exists."), $file_name), MSG_ERR, __FILE__, __LINE__);
270                $app->logMsg(sprintf('The uploaded file %s does not have a unique filename.', $file_name), LOG_WARNING, __FILE__, __LINE__);
271                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_USER_ERR_NOT_UNIQUE);
272                continue;
273            }
274
275            // If the file name has no extension, use the mime-type to choose one.
276            if (!preg_match('/\.[^.]{1,5}$/', $file_name) && function_exists('mime_content_type')) {
277                if ($ext = array_search(mime_content_type($files['tmp_name'][$i]), $this->mime_extension_map)) {
278                    $file_name .= ".$ext";
279                }
280            }
281
282            // Clean the file name of bad characters.
283            $file_name = $this->cleanFileName($file_name);
284
285            // FINAL path and file name, lowercase extension.
286            $file_extension = mb_strtolower($this->getFilenameExtension($file_name));
287            $file_name = sprintf('%s.%s', mb_substr($file_name, 0, mb_strrpos($file_name, '.')), $file_extension);
288            $file_path_name = sprintf('%s/%s', $this->getParam('upload_path'), $file_name);
289
290            // Move the file to the final place.
291            if (move_uploaded_file($files['tmp_name'][$i], $file_path_name)) {
292                chmod($file_path_name, $this->getParam('dest_file_perms'));
293                $app->logMsg(sprintf('File uploaded: %s', $file_path_name), LOG_INFO, __FILE__, __LINE__);
294                $this->_raiseMsg(sprintf(_("The file %s uploaded successfully."), $file_name), MSG_SUCCESS, __FILE__, __LINE__);
295                if (!isset($custom_file_name) && $files['name'][$i] != $file_name) {
296                    // Notify user if uploaded file name was modified (unless a custom file name will be used anyways).
297                    $this->_raiseMsg(sprintf(_("The file %s was renamed to %s."), $files['name'][$i], $file_name), MSG_NOTICE, __FILE__, __LINE__);
298                }
299                $new_file_names[] = array(
300                    'name' => $file_name,
301                    'mime' => $files['type'][$i],
302                    'size' => filesize($file_path_name),
303                    'extension' => $file_extension,
304                    'original_index' => $i,
305                    'original_name' => $files['name'][$i],
306                );
307            } else {
308                $this->_raiseMsg(sprintf(_("The file %s failed uploading."), $file_name), MSG_ERR, __FILE__, __LINE__);
309                $app->logMsg(sprintf('Moving file failed: %s -> %s', $files['tmp_name'][$i], $file_path_name), LOG_ALERT, __FILE__, __LINE__);
310                $this->errors[] = array('filename' => $file_name, 'errortype' => UPLOAD_USER_ERR_MOVE_FAILED);
311            }
312
313            // Check file extension with browsers interpretation of file type.
314            if (isset($this->mime_extension_map[$file_extension]) && $files['type'][$i] != $this->mime_extension_map[$file_extension]) {
315                $app->logMsg(sprintf('File extension (%s) does not match mime type (%s).', $file_extension, $files['type'][$i]), LOG_NOTICE, __FILE__, __LINE__);
316            }
317        }
318
319        // Return names of files uploaded (or empty array when none processed).
320        return $new_file_names;
321    }
322
323    /**
324     * Remove file within upload path.
325     *
326     * @access  public
327     * @param   string  $file_name  A name of a file.
328     * @param   bool    $use_glob   Set true to use glob to find the filename (using $file_name as a pattern)
329     * @return  bool                Success of operation.
330     */
331    function deleteFile($file_name, $use_glob=false)
332    {
333        $app =& App::getInstance();
334
335        // Ensure we have a upload directory.
336        if (!$this->getParam('upload_path')) {
337            $app->logMsg(sprintf('Upload directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
338            return false;
339        }
340
341        $file_path_name = $this->getParam('upload_path') . '/' . ($use_glob ? $this->getFilenameGlob($file_name) : $file_name);
342
343        if (!is_file($file_path_name)) {
344            $app->logMsg(sprintf('Error deleting nonexistent file: %s', $file_path_name), LOG_ERR, __FILE__, __LINE__);
345            return false;
346        } else if (unlink($file_path_name)) {
347            $app->logMsg(sprintf('Deleted file: %s', $file_path_name), LOG_INFO, __FILE__, __LINE__);
348            return true;
349        } else {
350            $this->_raiseMsg(sprintf(_("The file %s could not be deleted."), $file_name), MSG_ERR, __FILE__, __LINE__);
351            $app->logMsg(sprintf('Failed deleting file: %s', $file_path_name), LOG_ERR, __FILE__, __LINE__);
352            return false;
353        }
354    }
355
356    /**
357     * Renames a file within the upload path.
358     *
359     * @access  public
360     * @param   string  $old_name   The currently existing file name.
361     * @param   string  $new_name   The new name for this file.
362     * @return  bool                Success of operation.
363     */
364    function moveFile($old_name, $new_name)
365    {
366        $app =& App::getInstance();
367
368        // Ensure we have an upload directory.
369        if (!$this->getParam('upload_path')) {
370            $app->logMsg(sprintf('Upload directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
371            return false;
372        }
373
374        $old_file_path_name = $this->getParam('upload_path') . '/' . $old_name;
375        $new_file_path_name = $this->getParam('upload_path') . '/' . $new_name;
376        if (file_exists($old_file_path_name)) {
377            if (rename($old_file_path_name, $new_file_path_name)) {
378                $this->_raiseMsg(sprintf(_("The file %s has been renamed to %s."), basename($old_file_path_name), basename($new_file_path_name)), MSG_NOTICE, __FILE__, __LINE__);
379                $app->logMsg(sprintf('File renamed from %s to %s', $old_file_path_name, $new_file_path_name), LOG_DEBUG, __FILE__, __LINE__);
380            } else {
381                $this->_raiseMsg(sprintf(_("Error renaming file to %s"), $new_file_path_name), MSG_WARNING, __FILE__, __LINE__);
382                $app->logMsg(sprintf('Error renaming file to %s', $new_file_path_name), LOG_WARNING, __FILE__, __LINE__);
383                return false;
384            }
385        } else {
386            $this->_raiseMsg(sprintf(_("Couldn't rename nonexistent file %s."), $old_name), MSG_WARNING, __FILE__, __LINE__);
387            $app->logMsg(sprintf('Error renaming nonexistent file: %s', $old_file_path_name), LOG_WARNING, __FILE__, __LINE__);
388            return false;
389        }
390    }
391
392    /**
393     * Tests if a file exists within the current upload_path.
394     *
395     * @access  public
396     * @param   string  $file_name  A name of a file.
397     * @return  bool                Existence of file.
398     */
399    function exists($file_name)
400    {
401        $app =& App::getInstance();
402
403        // Ensure we have a upload directory.
404        if (!$this->getParam('upload_path')) {
405            $app->logMsg(sprintf('Upload directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
406            return false;
407        }
408
409        return file_exists($this->getParam('upload_path') . '/' . $file_name);
410    }
411
412    /**
413     * Get filename by glob pattern. Searches a directory for an image that matches the
414     * specified glob pattern and returns the filename of the first file found.
415     *
416     * @access  public
417     * @param   string  $pattern   Pattern to match filename.
418     * @return  string filename on success, empty string on failure.
419     * @author  Quinn Comendant <quinn@strangecode.com>
420     * @since   15 Nov 2005 20:55:22
421     */
422    function getFilenameGlob($pattern)
423    {
424        $file_list = glob(sprintf('%s/%s', $this->getParam('upload_path'), $pattern));
425        if (isset($file_list[0])) {
426            return basename($file_list[0]);
427        } else {
428            return '';
429        }
430    }
431
432    /**
433     * Returns an array of file names that failed uploading.
434     *
435     * @access  public
436     * @return  array   List of file names.
437     */
438    function getErrors()
439    {
440        return $this->errors;
441    }
442
443    /**
444     * Determintes if any errors occured while calling the Upload::process method.
445     *
446     * @access  public
447     */
448    function anyErrors()
449    {
450        return sizeof($this->errors) > 0;
451    }
452
453    /**
454     * Removes unsafe characters from file name.
455     *
456     * @access  public
457     * @param   string  $file_name  A name of a file.
458     * @return  string              The same name, but cleaned.
459     */
460    function cleanFileName($file_name)
461    {
462        $bad  = 'áéíóúàÚìòùÀëïöÌÁÉÍÓÚÀÈÌÒÙÄËÏÖÜâêîÎûÂÊÎÔÛñçÇ@';
463        $good = 'aeiouaeiouaeiouAEIOUAEIOUAEIOUaeiouAEIOUncCa';
464        $file_name = trim($file_name);
465        $file_name = strtr($file_name, $bad, $good);
466        $file_name = preg_replace('/[^-\w.,~_=+()]/i', '_', $file_name);
467        $file_name = mb_substr($file_name, 0, 250);
468        return $file_name;
469    }
470
471
472    /**
473     * Returns the extention of a file name, or an empty string if non exists.
474     *
475     * @access  public
476     * @param   string  $file_name  A name of a file, with extention after a dot.
477     * @return  string              The value found after the dot
478     */
479    function getFilenameExtension($file_name)
480    {
481        preg_match('/.*?\.(\w+)$/i', trim($file_name), $ext);
482        return isset($ext[1]) ? $ext[1] : '';
483    }
484
485    /**
486     * An alias for $app->raiseMsg that only sends messages configured by display_messages.
487     *
488     * @access public
489     *
490     * @param string $message The text description of the message.
491     * @param int    $type    The type of message: MSG_NOTICE,
492     *                        MSG_SUCCESS, MSG_WARNING, or MSG_ERR.
493     * @param string $file    __FILE__.
494     * @param string $line    __LINE__.
495     */
496    function _raiseMsg($message, $type, $file, $line)
497    {
498        $app =& App::getInstance();
499
500        if ($this->getParam('display_messages') === true || (is_int($this->getParam('display_messages')) && $this->getParam('display_messages') & $type > 0)) {
501            $app->raiseMsg($message, $type, $file, $line);
502        }
503    }
504}
505
506?>
Note: See TracBrowser for help on using the repository browser.