Back to index

php5  5.3.10
php_open_temporary_file.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Zeev Suraski <zeev@zend.com>                                 |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: php_open_temporary_file.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 
00023 #include <errno.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 
00028 #ifdef PHP_WIN32
00029 #define O_RDONLY _O_RDONLY
00030 #include "win32/param.h"
00031 #include "win32/winutil.h"
00032 #elif defined(NETWARE)
00033 #ifdef USE_WINSOCK
00034 #include <novsock2.h>
00035 #else
00036 #include <sys/socket.h>
00037 #endif
00038 #include <sys/param.h>
00039 #else
00040 #include <sys/param.h>
00041 #include <sys/socket.h>
00042 #include <netinet/in.h>
00043 #include <netdb.h>
00044 #if HAVE_ARPA_INET_H
00045 #include <arpa/inet.h>
00046 #endif
00047 #endif
00048 #ifdef HAVE_SYS_TIME_H
00049 #include <sys/time.h>
00050 #endif
00051 
00052 #ifdef HAVE_SYS_FILE_H
00053 #include <sys/file.h>
00054 #endif
00055 
00056 #if !defined(P_tmpdir)
00057 #define P_tmpdir ""
00058 #endif
00059 
00060 /* {{{ php_do_open_temporary_file */
00061 
00062 /* Loosely based on a tempnam() implementation by UCLA */
00063 
00064 /*
00065  * Copyright (c) 1988, 1993
00066  *      The Regents of the University of California.  All rights reserved.
00067  *
00068  * Redistribution and use in source and binary forms, with or without
00069  * modification, are permitted provided that the following conditions
00070  * are met:
00071  * 1. Redistributions of source code must retain the above copyright
00072  *    notice, this list of conditions and the following disclaimer.
00073  * 2. Redistributions in binary form must reproduce the above copyright
00074  *    notice, this list of conditions and the following disclaimer in the
00075  *    documentation and/or other materials provided with the distribution.
00076  * 3. All advertising materials mentioning features or use of this software
00077  *    must display the following acknowledgement:
00078  *      This product includes software developed by the University of
00079  *      California, Berkeley and its contributors.
00080  * 4. Neither the name of the University nor the names of its contributors
00081  *    may be used to endorse or promote products derived from this software
00082  *    without specific prior written permission.
00083  *
00084  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00085  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00086  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00087  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00088  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00089  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00090  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00091  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00092  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00093  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00094  * SUCH DAMAGE.
00095  */
00096 
00097 static int php_do_open_temporary_file(const char *path, const char *pfx, char **opened_path_p TSRMLS_DC)
00098 {
00099        char *trailing_slash;
00100        char *opened_path;
00101        char cwd[MAXPATHLEN];
00102        cwd_state new_state;
00103        int fd = -1;
00104 #ifndef HAVE_MKSTEMP
00105        int open_flags = O_CREAT | O_TRUNC | O_RDWR
00106 #ifdef PHP_WIN32
00107               | _O_BINARY
00108 #endif
00109               ;
00110 #endif
00111 
00112        if (!path || !path[0]) {
00113               return -1;
00114        }
00115 
00116 #ifdef PHP_WIN32
00117        if (!php_win32_check_trailing_space(pfx, (const int)strlen(pfx))) {
00118               SetLastError(ERROR_INVALID_NAME);
00119               return -1;
00120        }
00121 #endif
00122 
00123        if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
00124               cwd[0] = '\0';
00125        }
00126 
00127        new_state.cwd = strdup(cwd);
00128        new_state.cwd_length = strlen(cwd);
00129 
00130        if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
00131               free(new_state.cwd);
00132               return -1;
00133        }
00134 
00135        if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) {
00136               trailing_slash = "";
00137        } else {
00138               trailing_slash = "/";
00139        }
00140 
00141        if (spprintf(&opened_path, 0, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
00142               efree(opened_path);
00143               free(new_state.cwd);
00144               return -1;
00145        }
00146 
00147 #ifdef PHP_WIN32
00148 
00149        if (GetTempFileName(new_state.cwd, pfx, 0, opened_path)) {
00150               /* Some versions of windows set the temp file to be read-only,
00151                * which means that opening it will fail... */
00152               if (VCWD_CHMOD(opened_path, 0600)) {
00153                      efree(opened_path);
00154                      free(new_state.cwd);
00155                      return -1;
00156               }
00157               fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600);
00158        }
00159 
00160 #elif defined(HAVE_MKSTEMP)
00161        fd = mkstemp(opened_path);
00162 #else
00163        if (mktemp(opened_path)) {
00164               fd = VCWD_OPEN(opened_path, open_flags);
00165        }
00166 #endif
00167 
00168        if (fd == -1 || !opened_path_p) {
00169               efree(opened_path);
00170        } else {
00171               *opened_path_p = opened_path;
00172        }
00173        free(new_state.cwd);
00174        return fd;
00175 }
00176 /* }}} */
00177 
00178 /* Cache the chosen temporary directory. */
00179 static char* temporary_directory;
00180 
00181 PHPAPI void php_shutdown_temporary_directory(void)
00182 {
00183        if (temporary_directory) {
00184               free(temporary_directory);
00185               temporary_directory = NULL;
00186        }
00187 }
00188 
00189 /*
00190  *  Determine where to place temporary files.
00191  */
00192 PHPAPI const char* php_get_temporary_directory(void)
00193 {
00194        /* Did we determine the temporary directory already? */
00195        if (temporary_directory) {
00196               return temporary_directory;
00197        }
00198 
00199 #ifdef PHP_WIN32
00200        /* We can't count on the environment variables TEMP or TMP,
00201         * and so must make the Win32 API call to get the default
00202         * directory for temporary files.  Note this call checks
00203         * the environment values TMP and TEMP (in order) first.
00204         */
00205        {
00206               char sTemp[MAX_PATH];
00207               DWORD len = GetTempPath(sizeof(sTemp),sTemp);
00208               assert(0 < len);  /* should *never* fail! */
00209               if (sTemp[len - 1] == DEFAULT_SLASH) {
00210                      temporary_directory = zend_strndup(sTemp, len - 1);
00211               } else {
00212                      temporary_directory = zend_strndup(sTemp, len);
00213               }
00214               return temporary_directory;
00215        }
00216 #else
00217        /* On Unix use the (usual) TMPDIR environment variable. */
00218        {
00219               char* s = getenv("TMPDIR");
00220               if (s && *s) {
00221                      int len = strlen(s);
00222 
00223                      if (s[len - 1] == DEFAULT_SLASH) {
00224                             temporary_directory = zend_strndup(s, len - 1);
00225                      } else {
00226                             temporary_directory = zend_strndup(s, len);
00227                      }
00228 
00229                      return temporary_directory;
00230               }
00231        }
00232 #ifdef P_tmpdir
00233        /* Use the standard default temporary directory. */
00234        if (P_tmpdir) {
00235               temporary_directory = strdup(P_tmpdir);
00236               return temporary_directory;
00237        }
00238 #endif
00239        /* Shouldn't ever(!) end up here ... last ditch default. */
00240        temporary_directory = strdup("/tmp");
00241        return temporary_directory;
00242 #endif
00243 }
00244 
00245 /* {{{ php_open_temporary_file
00246  *
00247  * Unlike tempnam(), the supplied dir argument takes precedence
00248  * over the TMPDIR environment variable
00249  * This function should do its best to return a file pointer to a newly created
00250  * unique file, on every platform.
00251  */
00252 PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, char **opened_path_p, zend_bool open_basedir_check TSRMLS_DC)
00253 {
00254        int fd;
00255        const char *temp_dir;
00256 
00257        if (!pfx) {
00258               pfx = "tmp.";
00259        }
00260        if (opened_path_p) {
00261               *opened_path_p = NULL;
00262        }
00263 
00264        if (!dir || *dir == '\0') {
00265 def_tmp:
00266               temp_dir = php_get_temporary_directory();
00267 
00268               if (temp_dir && *temp_dir != '\0' && (!open_basedir_check || !php_check_open_basedir(temp_dir TSRMLS_CC))) {
00269                      return php_do_open_temporary_file(temp_dir, pfx, opened_path_p TSRMLS_CC);
00270               } else {
00271                      return -1;
00272               }
00273        }
00274 
00275        /* Try the directory given as parameter. */
00276        fd = php_do_open_temporary_file(dir, pfx, opened_path_p TSRMLS_CC);
00277        if (fd == -1) {
00278               /* Use default temporary directory. */
00279               goto def_tmp;
00280        }
00281        return fd;
00282 }
00283 
00284 PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
00285 {
00286        return php_open_temporary_fd_ex(dir, pfx, opened_path_p, 0 TSRMLS_CC);
00287 }
00288 
00289 PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
00290 {
00291        FILE *fp;
00292        int fd = php_open_temporary_fd(dir, pfx, opened_path_p TSRMLS_CC);
00293 
00294        if (fd == -1) {
00295               return NULL;
00296        }
00297        
00298        fp = fdopen(fd, "r+b");
00299        if (fp == NULL) {
00300               close(fd);
00301        }
00302        
00303        return fp;
00304 }
00305 /* }}} */
00306 
00307 /*
00308  * Local variables:
00309  * tab-width: 4
00310  * c-basic-offset: 4
00311  * End:
00312  * vim600: sw=4 ts=4 fdm=marker
00313  * vim<600: sw=4 ts=4
00314  */