Merge branch 'QA_3_3'
[phpmyadmin/dkf.git] / libraries / File.class.php
blob8f77fe4521f447649ca9e2ec281d31662c0500d3
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * file upload functions
6 * @version $Id$
7 * @package phpMyAdmin
8 */
10 /**
12 * @todo replace error messages with localized string
13 * @todo when uploading a file into a blob field, should we also consider using
14 * chunks like in import? UPDATE `table` SET `field` = `field` + [chunk]
15 * @package phpMyAdmin
17 class PMA_File
19 /**
20 * @var string the temporary file name
21 * @access protected
23 var $_name = null;
25 /**
26 * @var string the content
27 * @access protected
29 var $_content = null;
31 /**
32 * @var string the error message
33 * @access protected
35 var $_error_message = '';
37 /**
38 * @var bool whether the file is temporary or not
39 * @access protected
41 var $_is_temp = false;
43 /**
44 * @var string type of compression
45 * @access protected
47 var $_compression = null;
49 /**
50 * @var integer
52 var $_offset = 0;
54 /**
55 * @var integer size of chunk to read with every step
57 var $_chunk_size = 32768;
59 /**
60 * @var resource file handle
62 var $_handle = null;
64 /**
65 * @var boolean whether to decompress content before returning
67 var $_decompress = false;
69 /**
70 * @var string charset of file
72 var $_charset = null;
74 /**
75 * @staticvar string most recent BLOB repository reference
77 static $_recent_bs_reference = NULL;
79 /**
80 * constructor
82 * @access public
83 * @uses PMA_File::setName()
84 * @param string $name file name
86 function __construct($name = false)
88 if ($name) {
89 $this->setName($name);
93 /**
94 * destructor
96 * @see PMA_File::cleanUp()
97 * @access public
98 * @uses PMA_File::cleanUp()
100 function __destruct()
102 $this->cleanUp();
106 * deletes file if it is temporary, usally from a moved upload file
108 * @access public
109 * @uses PMA_File::delet()
110 * @uses PMA_File::isTemp()
111 * @return boolean success
113 function cleanUp()
115 if ($this->isTemp()) {
116 return $this->delete();
119 return true;
123 * deletes the file
125 * @access public
126 * @uses PMA_File::getName()
127 * @uses unlink()
128 * @return boolean success
130 function delete()
132 return unlink($this->getName());
136 * checks or sets the temp flag for this file
137 * file objects with temp flags are deleted with object destruction
139 * @access public
140 * @uses PMA_File::$_is_temp to set and read it
141 * @param boolean sets the temp flag
142 * @return boolean PMA_File::$_is_temp
144 function isTemp($is_temp = null)
146 if (null !== $is_temp) {
147 $this->_is_temp = (bool) $is_temp;
150 return $this->_is_temp;
154 * accessor
156 * @access public
157 * @uses PMA_File::$_name
158 * @param string $name file name
160 function setName($name)
162 $this->_name = trim($name);
166 * @access public
167 * @uses PMA_File::getName()
168 * @uses PMA_File::isUploaded()
169 * @uses PMA_File::checkUploadedFile()
170 * @uses PMA_File::isReadable()
171 * @uses PMA_File::$_content
172 * @uses function_exists()
173 * @uses file_get_contents()
174 * @uses filesize()
175 * @uses fread()
176 * @uses fopen()
177 * @uses bin2hex()
178 * @return string binary file content
180 function getContent($as_binary = true, $offset = 0, $length = null)
182 if (null === $this->_content) {
183 if ($this->isUploaded() && ! $this->checkUploadedFile()) {
184 return false;
187 if (! $this->isReadable()) {
188 return false;
191 if (function_exists('file_get_contents')) {
192 $this->_content = file_get_contents($this->getName());
193 } elseif ($size = filesize($this->getName())) {
194 $this->_content = fread(fopen($this->getName(), 'rb'), $size);
198 if (! empty($this->_content) && $as_binary) {
199 return '0x' . bin2hex($this->_content);
202 if (null !== $length) {
203 return substr($this->_content, $offset, $length);
204 } elseif ($offset > 0) {
205 return substr($this->_content, $offset);
208 return $this->_content;
212 * @access public
213 * @uses PMA_File::getName()
214 * @uses is_uploaded_file()
216 function isUploaded()
218 return is_uploaded_file($this->getName());
222 * accessor
224 * @access public
225 * @uses PMA_File::$name as return value
226 * @return string PMA_File::$_name
228 function getName()
230 return $this->_name;
234 * @todo replace error message with localized string
235 * @access public
236 * @uses PMA_File::isUploaded()
237 * @uses PMA_File::setName()
238 * @uses PMA_File::$_error_message
239 * @param string name of file uploaded
240 * @return boolean success
242 function setUploadedFile($name)
244 $this->setName($name);
246 if (! $this->isUploaded()) {
247 $this->setName(null);
248 $this->_error_message = 'not an uploaded file';
249 return false;
252 return true;
256 * @access public
257 * @uses PMA_File::fetchUploadedFromTblChangeRequestMultiple()
258 * @uses PMA_File::setUploadedFile()
259 * @uses PMA_File::setRecentBLOBReference()
260 * @uses curl_setopt_array()
261 * @uses PMA_File::$_error_message
262 * @uses $GLOBALS['strUploadErrorIniSize']
263 * @uses $GLOBALS['strUploadErrorFormSize']
264 * @uses $GLOBALS['strUploadErrorPartial']
265 * @uses $GLOBALS['strUploadErrorNoTempDir']
266 * @uses $GLOBALS['strUploadErrorCantWrite']
267 * @uses $GLOBALS['strUploadErrorExtension']
268 * @uses $GLOBALS['strUploadErrorUnknown']
269 * @uses $_FILES
270 * @param string $key a numeric key used to identify the different rows
271 * @param string $primary_key
272 * @return boolean success
274 function setUploadedFromTblChangeRequest($key, $primary = null)
276 if (! isset($_FILES['fields_upload_' . $key])) {
277 return false;
280 $file = $_FILES['fields_upload_' . $key];
282 if (null !== $primary) {
283 $file = PMA_File::fetchUploadedFromTblChangeRequestMultiple($file, $primary);
286 // for blobstreaming
287 $is_bs_upload = FALSE;
289 // check if this field requires a repository upload
290 if (isset($_REQUEST['upload_blob_repo_' . $key]))
291 $is_bs_upload = ($_REQUEST['upload_blob_repo_' . $key]['multi_edit'][0] == "on") ? TRUE : FALSE;
293 // if request is an upload to the BLOB repository
294 if ($is_bs_upload)
296 // load PMA configuration
297 $PMA_Config = $GLOBALS['PMA_Config'];
299 // if PMA configuration is loaded
300 if (!empty($PMA_Config))
302 // load BS variables from PMA configuration
303 $pluginsExist = $PMA_Config->get('BLOBSTREAMING_PLUGINS_EXIST');
304 $curlExists = $PMA_Config->get('CURL_EXISTS');
305 $bs_database = $PMA_Config->get('BLOBSTREAMABLE_DATABASES');
306 $bs_database = $bs_database[$_REQUEST['db']];
308 $allBSTablesExist = TRUE;
310 // determine if plugins and curl exist
311 if ($pluginsExist && $curlExists)
313 foreach ($bs_database as $table_key=>$table)
315 if (!$bs_database[$table_key]['Exists'])
317 $allBSTablesExist = FALSE;
318 break;
322 else
323 $allBSTablesExist = FALSE;
325 // if necessary BS tables exist
326 if ($allBSTablesExist)
328 // setup bs variables for uploading
329 $bs_server = $PMA_Config->get('BLOBSTREAMING_SERVER');
330 $bs_db = $_REQUEST['db'];
331 $bs_table = $_REQUEST['table'];
333 // setup file handle and related variables
334 $tmp_file = fopen($file['tmp_name'], 'r');
335 $tmp_file_type = $file['type'];
336 $tmp_file_size = $file['size'];
338 if (!$tmp_file_type)
339 $tmp_file_type = NULL;
341 // if none of the required variables contain data, return with an unknown error message
342 if (!$bs_server || !$bs_db || !$bs_table || !$tmp_file || !$tmp_file_size)
344 $this->_error_message = $GLOBALS['strUploadErrorUnknown'];
345 return FALSE;
347 else
348 $bs_server_path = 'http://' . $bs_server . '/' . $bs_db . '/' . $bs_table;
350 // init curl handle
351 $curlHnd = curl_init ($bs_server_path);
353 // if curl handle init successful
354 if ($curlHnd)
356 // specify custom header
357 $customHeader = array(
358 "Accept-Language: en-us;en;q=0;5",
359 "Accept-Charset: ISO-8859-1;utf-8;q=0.7,*;q=0.7",
360 "Content-type: $tmp_file_type"
363 // specify CURL options in array
364 $curlOptArr = array(
365 CURLOPT_PUT => TRUE,
366 CURLOPT_HEADER => TRUE,
367 CURLOPT_HTTPHEADER => $customHeader,
368 CURLOPT_INFILESIZE => $tmp_file_size,
369 CURLOPT_INFILE => $tmp_file,
370 CURLOPT_RETURNTRANSFER => TRUE
373 // pass array of options to curl handle setup function
374 curl_setopt_array($curlHnd, $curlOptArr);
376 // execute curl request and retrieve error message(s) (if any)
377 $ret = curl_exec($curlHnd);
378 $errRet = curl_error($curlHnd);
380 // close curl handle
381 curl_close($curlHnd);
383 // split entire string into array of lines
384 $retArr = explode("\r\n", $ret);
386 // check each line as a valid string of a BLOB reference
387 foreach ($retArr as $value)
388 if (strlen($value) > strlen("~*$bs_db/~") && "~*$bs_db/~" == substr($value, 0, strlen($bs_db) + 4))
390 // is a valid reference, so set as current and break
391 PMA_File::setRecentBLOBReference($value);
392 break;
395 // close file handle
396 if ($tmp_file)
397 fclose($tmp_file);
398 } // end if ($curlHnd)
399 } // end if ($allBSTablesExist)
400 } // end if ($PMA_Config)
401 } // end if ($is_bs_upload)
403 // check for file upload errors
404 switch ($file['error']) {
405 // cybot_tm: we do not use the PHP constants here cause not all constants
406 // are defined in all versions of PHP - but the correct constants names
407 // are given as comment
408 case 0: //UPLOAD_ERR_OK:
409 return $this->setUploadedFile($file['tmp_name']);
410 break;
411 case 4: //UPLOAD_ERR_NO_FILE:
412 break;
413 case 1: //UPLOAD_ERR_INI_SIZE:
414 $this->_error_message = $GLOBALS['strUploadErrorIniSize'];
415 break;
416 case 2: //UPLOAD_ERR_FORM_SIZE:
417 $this->_error_message = $GLOBALS['strUploadErrorFormSize'];
418 break;
419 case 3: //UPLOAD_ERR_PARTIAL:
420 $this->_error_message = $GLOBALS['strUploadErrorPartial'];
421 break;
422 case 6: //UPLOAD_ERR_NO_TMP_DIR:
423 $this->_error_message = $GLOBALS['strUploadErrorNoTempDir'];
424 break;
425 case 7: //UPLOAD_ERR_CANT_WRITE:
426 $this->_error_message = $GLOBALS['strUploadErrorCantWrite'];
427 break;
428 case 8: //UPLOAD_ERR_EXTENSION:
429 $this->_error_message = $GLOBALS['strUploadErrorExtension'];
430 break;
431 default:
432 $this->_error_message = $GLOBALS['strUploadErrorUnknown'];
433 } // end switch
435 return false;
439 * strips some dimension from the multi-dimensional array from $_FILES
441 * <code>
442 * $file['name']['multi_edit'][$primary] = [value]
443 * $file['type']['multi_edit'][$primary] = [value]
444 * $file['size']['multi_edit'][$primary] = [value]
445 * $file['tmp_name']['multi_edit'][$primary] = [value]
446 * $file['error']['multi_edit'][$primary] = [value]
448 * // becomes:
450 * $file['name'] = [value]
451 * $file['type'] = [value]
452 * $file['size'] = [value]
453 * $file['tmp_name'] = [value]
454 * $file['error'] = [value]
455 * </code>
457 * @todo re-check if requirements changes to PHP >= 4.2.0
458 * @access public
459 * @static
460 * @param array $file the array
461 * @param string $primary
462 * @return array
464 function fetchUploadedFromTblChangeRequestMultiple($file, $primary)
466 $new_file = array(
467 'name' => $file['name']['multi_edit'][$primary],
468 'type' => $file['type']['multi_edit'][$primary],
469 'size' => $file['size']['multi_edit'][$primary],
470 'tmp_name' => $file['tmp_name']['multi_edit'][$primary],
471 'error' => $file['error']['multi_edit'][$primary],
474 return $new_file;
478 * sets the name if the file to the one selected in the tbl_change form
480 * @access public
481 * @uses $_REQUEST
482 * @uses PMA_File::setLocalSelectedFile()
483 * @uses is_string()
484 * @param string $key a numeric key used to identify the different rows
485 * @param string $primary_key
486 * @return boolean success
488 function setSelectedFromTblChangeRequest($key, $primary = null)
490 if (null !== $primary) {
491 if (! empty($_REQUEST['fields_uploadlocal_' . $key]['multi_edit'][$primary])
492 && is_string($_REQUEST['fields_uploadlocal_' . $key]['multi_edit'][$primary])) {
493 // ... whether with multiple rows ...
494 // for blobstreaming
495 $is_bs_upload = FALSE;
497 // check if this field requires a repository upload
498 if (isset($_REQUEST['upload_blob_repo_' . $key]))
499 $is_bs_upload = ($_REQUEST['upload_blob_repo_' . $key]['multi_edit'][0] == "on") ? TRUE : FALSE;
501 // is a request to upload file to BLOB repository using uploadDir mechanism
502 if ($is_bs_upload)
504 // load PMA configuration
505 $PMA_Config = $GLOBALS['PMA_Config'];
507 // if the PMA configuration was loaded
508 if (!empty($PMA_Config))
510 // load BS variables from PMA configuration
511 $pluginsExist = $PMA_Config->get('BLOBSTREAMING_PLUGINS_EXIST');
512 $curlExists = $PMA_Config->get('CURL_EXISTS');
513 $bs_database = $PMA_Config->get('BLOBSTREAMABLE_DATABASES');
514 $bs_database = $bs_database[$_REQUEST['db']];
516 $allBSTablesExist = TRUE;
518 // if plugins and curl exist
519 if ($pluginsExist && $curlExists)
521 foreach ($bs_database as $table_key=>$table)
523 if (!$bs_database[$table_key]['Exists'])
525 $allBSTablesExist = FALSE;
526 break;
530 else
531 $allBSTablesExist = FALSE;
533 // if necessary BS tables exist
534 if ($allBSTablesExist)
536 // load BS variables
537 $bs_server = $PMA_Config->get('BLOBSTREAMING_SERVER');
538 $bs_db = $_REQUEST['db'];
539 $bs_table = $_REQUEST['table'];
541 // setup uploadDir mechanism and file variables
542 $tmp_filename = $GLOBALS['cfg']['UploadDir'] . '/' . $_REQUEST['fields_uploadlocal_' . $key]['multi_edit'][$primary];
543 $tmp_file = fopen($tmp_filename, 'r');
544 $tmp_file_size = filesize($tmp_filename);
546 // check if fileinfo library exists
547 if ($PMA_Config->get('FILEINFO_EXISTS'))
549 // attempt to init fileinfo
550 $finfo = finfo_open(FILEINFO_MIME);
552 // fileinfo exists
553 if ($finfo)
555 // pass in filename to fileinfo and close fileinfo handle after
556 $tmp_file_type = finfo_file($finfo, $tmp_filename);
557 finfo_close($finfo);
560 else // no fileinfo library exists, use file command
561 $tmp_file_type = exec("file -bi " . escapeshellarg($tmp_filename));
563 if (!$tmp_file_type)
564 $tmp_file_type = NULL;
566 // necessary variables aren't loaded, return error message (unknown error)
567 if (!$bs_server || !$bs_db || !$bs_table || !$tmp_file || !$tmp_file_size)
569 $this->_error_message = $GLOBALS['strUploadErrorUnknown'];
570 return FALSE;
572 else
573 $bs_server_path = 'http://' . $bs_server . '/' . $bs_db . '/' . $bs_table;
575 // init curl handle
576 $curlHnd = curl_init ($bs_server_path);
578 // curl handle exists
579 if ($curlHnd)
581 // specify custom header
582 $customHeader = array(
583 "Accept-Language: en-us;en;q=0;5",
584 "Accept-Charset: ISO-8859-1;utf-8;q=0.7,*;q=0.7",
585 "Content-type: $tmp_file_type"
588 // specify custom curl options
589 $curlOptArr = array(
590 CURLOPT_PUT => TRUE,
591 CURLOPT_HEADER => TRUE,
592 CURLOPT_HTTPHEADER => $customHeader,
593 CURLOPT_INFILESIZE => $tmp_file_size,
594 CURLOPT_INFILE => $tmp_file,
595 CURLOPT_RETURNTRANSFER => TRUE
598 // setup custom curl options (as specified in above array)
599 curl_setopt_array($curlHnd, $curlOptArr);
601 // execute curl request and retrieve error message(s) (if any)
602 $ret = curl_exec($curlHnd);
603 $errRet = curl_error($curlHnd);
605 // close curl handle
606 curl_close($curlHnd);
608 // split return string into lines
609 $retArr = explode("\r\n", $ret);
611 // check subsequent lines for valid BLOB reference string
612 foreach ($retArr as $value)
613 if (strlen($value) > strlen("~*$bs_db/~") && "~*$bs_db/~" == substr($value, 0, strlen($bs_db) + 4))
615 // is a valid reference, so set as current and break
616 PMA_File::setRecentBLOBReference($value);
617 break;
620 // close file handle
621 if ($tmp_file)
622 fclose($tmp_file);
623 } // end if ($curlHnd)
624 } // end if ($allBSTablesExist)
625 } // end if ($PMA_Config)
626 } // end if ($is_bs_upload)
628 return $this->setLocalSelectedFile($_REQUEST['fields_uploadlocal_' . $key]['multi_edit'][$primary]);
629 } else {
630 return false;
632 } elseif (! empty($_REQUEST['fields_uploadlocal_' . $key])
633 && is_string($_REQUEST['fields_uploadlocal_' . $key])) {
634 // for blobstreaming
635 $is_bs_upload = FALSE;
637 // check if this field requires a repository upload
638 if (isset($_REQUEST['upload_blob_repo_' . $key]))
639 $is_bs_upload = ($_REQUEST['upload_blob_repo_' . $key]['multi_edit'][0] == "on") ? TRUE : FALSE;
641 // is a request to upload file to BLOB repository using uploadDir mechanism
642 if ($is_bs_upload)
644 // load PMA configuration
645 $PMA_Config = $GLOBALS['PMA_Config'];
647 // if the PMA configuration was loaded
648 if (!empty($PMA_Config))
650 // load BS variables from PMA configuration
651 $pluginsExist = $PMA_Config->get('BLOBSTREAMING_PLUGINS_EXIST');
652 $curlExists = $PMA_Config->get('CURL_EXISTS');
653 $bs_database = $PMA_Config->get('BLOBSTREAMABLE_DATABASES');
654 $bs_database = $bs_database[$_REQUEST['db']];
656 $allBSTablesExist = TRUE;
658 // if plugins and curl exist
659 if ($pluginsExist && $curlExists)
661 foreach ($bs_database as $table_key=>$table)
663 if (!$bs_database[$table_key]['Exists'])
665 $allBSTablesExist = FALSE;
666 break;
670 else
671 $allBSTablesExist = FALSE;
673 if ($allBSTablesExist)
675 // load BS variables
676 $bs_server = $PMA_Config->get('BLOBSTREAMING_SERVER');
677 $bs_db = $_REQUEST['db'];
678 $bs_table = $_REQUEST['table'];
680 // setup uploadDir mechanism and file variables
681 $tmp_filename = $GLOBALS['cfg']['UploadDir'] . '/' . $_REQUEST['fields_uploadlocal_' . $key]['multi_edit'][$primary];
682 $tmp_file = fopen($tmp_filename, 'r');
683 $tmp_file_size = filesize($tmp_filename);
685 // check if fileinfo library exists
686 if ($PMA_Config->get('FILEINFO_EXISTS'))
688 // attempt to init fileinfo
689 $finfo = finfo_open(FILEINFO_MIME);
691 // if fileinfo exists
692 if ($finfo)
694 // pass in filename to fileinfo and close fileinfo handle after
695 $tmp_file_type = finfo_file($finfo, $tmp_filename);
696 finfo_close($finfo);
699 else // no fileinfo library exists, use file command
700 $tmp_file_type = exec("file -bi " . escapeshellarg($tmp_filename));
702 if (!$tmp_file_type)
703 $tmp_file_type = NULL;
705 // necessary variables aren't loaded, return error message (unknown error)
706 if (!$bs_server || !$bs_db || !$bs_table || !$tmp_file || !$tmp_file_size)
708 $this->_error_message = $GLOBALS['strUploadErrorUnknown'];
709 return FALSE;
711 else
712 $bs_server_path = 'http://' . $bs_server . '/' . $bs_db . '/' . $bs_table;
714 // init curl handle
715 $curlHnd = curl_init ($bs_server_path);
717 // if curl handle exists
718 if ($curlHnd)
720 // specify custom header
721 $customHeader = array(
722 "Accept-Language: en-us;en;q=0;5",
723 "Accept-Charset: ISO-8859-1;utf-8;q=0.7,*;q=0.7",
724 "Content-type: $tmp_file_type"
727 // specify custom curl options
728 $curlOptArr = array(
729 CURLOPT_PUT => TRUE,
730 CURLOPT_HEADER => TRUE,
731 CURLOPT_HTTPHEADER => $customHeader,
732 CURLOPT_INFILESIZE => $tmp_file_size,
733 CURLOPT_INFILE => $tmp_file,
734 CURLOPT_RETURNTRANSFER => TRUE
737 // setup custom curl options (as specified in above array)
738 curl_setopt_array($curlHnd, $curlOptArr);
740 // execute curl request and retrieve error message(s) (if any)
741 $ret = curl_exec($curlHnd);
742 $errRet = curl_error($curlHnd);
744 // close curl handle
745 curl_close($curlHnd);
747 // split return string into lines
748 $retArr = explode("\r\n", $ret);
750 // check subsequent lines for valid BLOB reference string
751 foreach ($retArr as $value)
752 if (strlen($value) > strlen("~*$bs_db/~") && "~*$bs_db/~" == substr($value, 0, strlen($bs_db) + 4))
754 // is a valid reference, so set as current and break
755 PMA_File::setRecentBLOBReference($value);
756 break;
759 // close file handle
760 if ($tmp_file)
761 fclose($tmp_file);
762 } // end if ($curlHnd)
763 } // end if ($allBSTablesExist)
764 } // end if ($PMA_Config)
765 } // end if ($is_bs_upload)
767 return $this->setLocalSelectedFile($_REQUEST['fields_uploadlocal_' . $key]);
770 return false;
774 * @access public
775 * @uses PMA_File->$_error_message as return value
776 * @return string error message
778 function getError()
780 return $this->_error_message;
784 * @access public
785 * @uses PMA_File->$_error_message to check it
786 * @return boolean whether an error occured or not
788 function isError()
790 return ! empty($this->_error_message);
794 * checks the superglobals provided if the tbl_change form is submitted
795 * and uses the submitted/selected file
797 * @access public
798 * @uses PMA_File::setUploadedFromTblChangeRequest()
799 * @uses PMA_File::setSelectedFromTblChangeRequest()
800 * @param string $key a numeric key used to identify the different rows
801 * @param string $primary_key
802 * @return boolean success
804 function checkTblChangeForm($key, $primary_key)
806 if ($this->setUploadedFromTblChangeRequest($key, $primary_key)) {
807 // well done ...
808 $this->_error_message = '';
809 return true;
811 } elseif ($this->setUploadedFromTblChangeRequest($key)) {
812 // well done ...
813 $this->_error_message = '';
814 return true;
816 } elseif ($this->setSelectedFromTblChangeRequest($key, $primary_key)) {
817 // well done ...
818 $this->_error_message = '';
819 return true;
821 } elseif ($this->setSelectedFromTblChangeRequest($key)) {
822 // well done ...
823 $this->_error_message = '';
824 return true;
827 // all failed, whether just no file uploaded/selected or an error
829 return false;
834 * @access public
835 * @uses $GLOBALS['strFileCouldNotBeRead']
836 * @uses PMA_File::setName()
837 * @uses PMA_securePath()
838 * @uses PMA_userDir()
839 * @uses $GLOBALS['cfg']['UploadDir']
840 * @param string $name
841 * @return boolean success
843 function setLocalSelectedFile($name)
845 if (empty($GLOBALS['cfg']['UploadDir'])) return false;
847 $this->setName(PMA_userDir($GLOBALS['cfg']['UploadDir']) . PMA_securePath($name));
848 if (! $this->isReadable()) {
849 $this->_error_message = $GLOBALS['strFileCouldNotBeRead'];
850 $this->setName(null);
851 return false;
854 return true;
858 * @access public
859 * @uses PMA_File::getName()
860 * @uses is_readable()
861 * @uses ob_start()
862 * @uses ob_end_clean()
863 * @return boolean whether the file is readable or not
865 function isReadable()
867 // suppress warnings from being displayed, but not from being logged
868 // any file access outside of open_basedir will issue a warning
869 ob_start();
870 $is_readable = is_readable($this->getName());
871 ob_end_clean();
872 return $is_readable;
876 * If we are on a server with open_basedir, we must move the file
877 * before opening it. The FAQ 1.11 explains how to create the "./tmp"
878 * directory - if needed
880 * @todo replace error message with localized string
881 * @todo move check of $cfg['TempDir'] into PMA_Config?
882 * @access public
883 * @uses $cfg['TempDir']
884 * @uses $GLOBALS['strFieldInsertFromFileTempDirNotExists']
885 * @uses PMA_File::isReadable()
886 * @uses PMA_File::getName()
887 * @uses PMA_File::setName()
888 * @uses PMA_File::isTemp()
889 * @uses PMA_File::$_error_message
890 * @uses is_dir()
891 * @uses mkdir()
892 * @uses chmod()
893 * @uses is_writable()
894 * @uses basename()
895 * @uses move_uploaded_file()
896 * @uses ob_start()
897 * @uses ob_end_clean()
898 * @return boolean whether uploaded fiel is fine or not
900 function checkUploadedFile()
902 if ($this->isReadable()) {
903 return true;
906 if (empty($GLOBALS['cfg']['TempDir']) || ! is_writable($GLOBALS['cfg']['TempDir'])) {
907 // cannot create directory or access, point user to FAQ 1.11
908 $this->_error_message = $GLOBALS['strFieldInsertFromFileTempDirNotExists'];
909 return false;
912 $new_file_to_upload = tempnam(realpath($GLOBALS['cfg']['TempDir']), basename($this->getName()));
914 // suppress warnings from being displayed, but not from being logged
915 // any file access outside of open_basedir will issue a warning
916 ob_start();
917 $move_uploaded_file_result = move_uploaded_file($this->getName(), $new_file_to_upload);
918 ob_end_clean();
919 if (! $move_uploaded_file_result) {
920 $this->_error_message = 'error while moving uploaded file';
921 return false;
924 $this->setName($new_file_to_upload);
925 $this->isTemp(true);
927 if (! $this->isReadable()) {
928 $this->_error_message = 'cannot read (moved) upload file';
929 return false;
932 return true;
936 * Detects what compression filse uses
938 * @todo move file read part into readChunk() or getChunk()
939 * @todo add support for compression plugins
940 * @uses $GLOBALS['strFileCouldNotBeRead']
941 * @uses PMA_File::$_compression to set it
942 * @uses PMA_File::getName()
943 * @uses fopen()
944 * @uses fread()
945 * @uses strlen()
946 * @uses fclose()
947 * @uses chr()
948 * @uses substr()
949 * @access protected
950 * @return string MIME type of compression, none for none
952 function _detectCompression()
954 // suppress warnings from being displayed, but not from being logged
955 // f.e. any file access outside of open_basedir will issue a warning
956 ob_start();
957 $file = fopen($this->getName(), 'rb');
958 ob_end_clean();
960 if (! $file) {
961 $this->_error_message = $GLOBALS['strFileCouldNotBeRead'];
962 return false;
966 * @todo
967 * get registered plugins for file compression
969 foreach (PMA_getPlugins($type = 'compression') as $plugin) {
970 if (call_user_func_array(array($plugin['classname'], 'canHandle'), array($this->getName()))) {
971 $this->setCompressionPlugin($plugin);
972 break;
977 $test = fread($file, 4);
978 $len = strlen($test);
979 fclose($file);
981 if ($len >= 2 && $test[0] == chr(31) && $test[1] == chr(139)) {
982 $this->_compression = 'application/gzip';
983 } elseif ($len >= 3 && substr($test, 0, 3) == 'BZh') {
984 $this->_compression = 'application/bzip2';
985 } elseif ($len >= 4 && $test == "PK\003\004") {
986 $this->_compression = 'application/zip';
987 } else {
988 $this->_compression = 'none';
991 return $this->_compression;
995 * whether the content should be decompressed before returned
997 function setDecompressContent($decompress)
999 $this->_decompress = (bool) $decompress;
1002 function getHandle()
1004 if (null === $this->_handle) {
1005 $this->open();
1007 return $this->_handle;
1010 function setHandle($handle)
1012 $this->_handle = $handle;
1018 function open()
1020 if (! $this->_decompress) {
1021 $this->_handle = @fopen($this->getName(), 'r');
1024 switch ($this->getCompression()) {
1025 case false:
1026 return false;
1027 case 'application/bzip2':
1028 if ($GLOBALS['cfg']['BZipDump'] && @function_exists('bzopen')) {
1029 $this->_handle = @bzopen($this->getName(), 'r');
1030 } else {
1031 $this->_error_message = sprintf($GLOBALS['strUnsupportedCompressionDetected'], $this->getCompression());
1032 return false;
1034 break;
1035 case 'application/gzip':
1036 if ($GLOBALS['cfg']['GZipDump'] && @function_exists('gzopen')) {
1037 $this->_handle = @gzopen($this->getName(), 'r');
1038 } else {
1039 $this->_error_message = sprintf($GLOBALS['strUnsupportedCompressionDetected'], $this->getCompression());
1040 return false;
1042 break;
1043 case 'application/zip':
1044 if ($GLOBALS['cfg']['ZipDump'] && @function_exists('zip_open')) {
1045 include_once './libraries/zip_extension.lib.php';
1046 $result = PMA_getZipContents($this->getName());
1047 if (! empty($result['error'])) {
1048 $this->_error_message = PMA_Message::rawError($result['error']);
1049 return false;
1050 } else {
1051 $this->content_uncompressed = $result['data'];
1053 unset($result);
1054 } else {
1055 $this->_error_message = sprintf($GLOBALS['strUnsupportedCompressionDetected'], $this->getCompression());
1056 return false;
1058 break;
1059 case 'none':
1060 $this->_handle = @fopen($this->getName(), 'r');
1061 break;
1062 default:
1063 $this->_error_message = sprintf($GLOBALS['strUnsupportedCompressionDetected'], $this->getCompression());
1064 return false;
1065 break;
1071 function getCharset()
1073 return $this->_charset;
1076 function setCharset($charset)
1078 $this->_charset = $charset;
1082 * @uses PMA_File::$_compression as return value
1083 * @uses PMA_File::detectCompression()
1084 * @return string MIME type of compression, none for none
1085 * @access public
1087 function getCompression()
1089 if (null === $this->_compression) {
1090 return $this->_detectCompression();
1093 return $this->_compression;
1097 * advances the file pointer in the file handle by $length bytes/chars
1099 * @param integer $length numbers of chars/bytes to skip
1100 * @return boolean
1101 * @todo this function is unused
1103 function advanceFilePointer($length)
1105 while ($length > 0) {
1106 // Disable read progresivity, otherwise we eat all memory!
1107 $read_multiply = 1; // required?
1108 $this->getNextChunk($length);
1109 $length -= $this->getChunkSize();
1114 * http://bugs.php.net/bug.php?id=29532
1115 * bzip reads a maximum of 8192 bytes on windows systems
1116 * @todo this function is unused
1118 function getNextChunk($max_size = null)
1120 if (null !== $max_size) {
1121 $size = min($max_size, $this->getChunkSize());
1122 } else {
1123 $size = $this->getChunkSize();
1126 // $result = $this->handler->getNextChunk($size);
1127 $result = '';
1128 switch ($this->getCompression()) {
1129 case 'application/bzip2':
1130 $result = '';
1131 while (strlen($result) < $size - 8192 && ! feof($this->getHandle())) {
1132 $result .= bzread($this->getHandle(), $size);
1134 break;
1135 case 'application/gzip':
1136 $result = gzread($this->getHandle(), $size);
1137 break;
1138 case 'application/zip':
1140 * if getNextChunk() is used some day,
1141 * replace this code by code similar to the one
1142 * in open()
1144 include_once './libraries/unzip.lib.php';
1145 $import_handle = new SimpleUnzip();
1146 $import_handle->ReadFile($this->getName());
1147 if ($import_handle->Count() == 0) {
1148 $this->_error_message = $GLOBALS['strNoFilesFoundInZip'];
1149 return false;
1150 } elseif ($import_handle->GetError(0) != 0) {
1151 $this->_error_message = $GLOBALS['strErrorInZipFile']
1152 . ' ' . $import_handle->GetErrorMsg(0);
1153 return false;
1154 } else {
1155 $result = $import_handle->GetData(0);
1158 break;
1159 case 'none':
1160 $result = fread($this->getHandle(), $size);
1161 break;
1162 default:
1163 return false;
1166 echo $size . ' - ';
1167 echo strlen($result) . ' - ';
1168 echo (@$GLOBALS['__len__'] += strlen($result)) . ' - ';
1169 echo $this->_error_message;
1170 echo '<hr />';
1172 if ($GLOBALS['charset_conversion']) {
1173 $result = PMA_convert_string($this->getCharset(), $GLOBALS['charset'], $result);
1174 } else {
1176 * Skip possible byte order marks (I do not think we need more
1177 * charsets, but feel free to add more, you can use wikipedia for
1178 * reference: <http://en.wikipedia.org/wiki/Byte_Order_Mark>)
1180 * @todo BOM could be used for charset autodetection
1182 if ($this->getOffset() === 0) {
1183 // UTF-8
1184 if (strncmp($result, "\xEF\xBB\xBF", 3) == 0) {
1185 $result = substr($result, 3);
1186 // UTF-16 BE, LE
1187 } elseif (strncmp($result, "\xFE\xFF", 2) == 0
1188 || strncmp($result, "\xFF\xFE", 2) == 0) {
1189 $result = substr($result, 2);
1194 $this->_offset += $size;
1195 if (0 === $result) {
1196 return true;
1198 return $result;
1201 function getOffset()
1203 return $this->_offset;
1206 function getChunkSize()
1208 return $this->_chunk_size;
1211 function setChunkSize($chunk_size)
1213 $this->_chunk_size = (int) $chunk_size;
1216 function getContentLength()
1218 return strlen($this->_content);
1221 function eof()
1223 if ($this->getHandle()) {
1224 return feof($this->getHandle());
1225 } else {
1226 return ($this->getOffset() >= $this->getContentLength());
1232 * sets reference to most recent BLOB repository reference
1234 * @access public
1235 * @param string - BLOB repository reference
1237 static function setRecentBLOBReference($ref)
1239 PMA_File::$_recent_bs_reference = $ref;
1243 * retrieves reference to most recent BLOB repository reference
1245 * @access public
1246 * @return string - most recent BLOB repository reference
1248 static function getRecentBLOBReference()
1250 $ref = PMA_File::$_recent_bs_reference;
1251 PMA_File::$_recent_bs_reference = NULL;
1253 return $ref;