Back to index

php5  5.3.10
mysqlnd_loaddata.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 2006-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   | Authors: Georg Richter <georg@mysql.com>                             |
00016   |          Andrey Hristov <andrey@mysql.com>                           |
00017   |          Ulf Wendel <uwendel@mysql.com>                              |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 #include "php.h"
00022 #include "php_globals.h"
00023 #include "mysqlnd.h"
00024 #include "mysqlnd_wireprotocol.h"
00025 #include "mysqlnd_priv.h"
00026 #include "mysqlnd_debug.h"
00027 
00028 
00029 #define ALLOC_CALLBACK_ARGS(a, b, c)\
00030 if (c) {\
00031        a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
00032        for (i = b; i < c; i++) {\
00033               a[i] = mnd_emalloc(sizeof(zval *));\
00034               MAKE_STD_ZVAL(*a[i]);\
00035        }\
00036 }
00037 
00038 #define FREE_CALLBACK_ARGS(a, b, c)\
00039 if (a) {\
00040        for (i = b; i < c; i++) {\
00041               zval_ptr_dtor(a[i]);\
00042               mnd_efree(a[i]);\
00043        }\
00044        mnd_efree(a);\
00045 }
00046 
00047 /* {{{ mysqlnd_local_infile_init */
00048 static
00049 int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS_DC)
00050 {
00051        MYSQLND_INFILE_INFO  *info;
00052        php_stream_context   *context = NULL;
00053 
00054        DBG_ENTER("mysqlnd_local_infile_init");
00055 
00056        info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
00057        if (!info) {
00058               DBG_RETURN(1);
00059        }
00060 
00061        *ptr = info;
00062 
00063        /* check open_basedir */
00064        if (PG(open_basedir)) {
00065               if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
00066                      strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
00067                      info->error_no = CR_UNKNOWN_ERROR;
00068                      DBG_RETURN(1);
00069               }
00070        }
00071 
00072        info->filename = filename;
00073        info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
00074 
00075        if (info->fd == NULL) {
00076               snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
00077               info->error_no = MYSQLND_EE_FILENOTFOUND;
00078               DBG_RETURN(1);
00079        }
00080 
00081        DBG_RETURN(0);
00082 }
00083 /* }}} */
00084 
00085 
00086 /* {{{ mysqlnd_local_infile_read */
00087 static
00088 int mysqlnd_local_infile_read(void *ptr, char *buf, unsigned int buf_len TSRMLS_DC)
00089 {
00090        MYSQLND_INFILE_INFO  *info = (MYSQLND_INFILE_INFO *)ptr;
00091        int count;
00092 
00093        DBG_ENTER("mysqlnd_local_infile_read");
00094 
00095        count = (int)php_stream_read(info->fd, buf, buf_len);
00096 
00097        if (count < 0) {
00098               strcpy(info->error_msg, "Error reading file");
00099               info->error_no = CR_UNKNOWN_ERROR;
00100        }
00101 
00102        DBG_RETURN(count);
00103 }
00104 /* }}} */
00105 
00106 
00107 /* {{{ mysqlnd_local_infile_error */
00108 static
00109 int    mysqlnd_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len TSRMLS_DC)
00110 {
00111        MYSQLND_INFILE_INFO  *info = (MYSQLND_INFILE_INFO *)ptr;
00112 
00113        DBG_ENTER("mysqlnd_local_infile_error");
00114 
00115        if (info) {
00116               strlcpy(error_buf, info->error_msg, error_buf_len);
00117               DBG_INF_FMT("have info, %d", info->error_no);
00118               DBG_RETURN(info->error_no);
00119        }
00120 
00121        strlcpy(error_buf, "Unknown error", error_buf_len);
00122        DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
00123        DBG_RETURN(CR_UNKNOWN_ERROR);
00124 }
00125 /* }}} */
00126 
00127 
00128 /* {{{ mysqlnd_local_infile_end */
00129 static
00130 void mysqlnd_local_infile_end(void *ptr TSRMLS_DC)
00131 {
00132        MYSQLND_INFILE_INFO  *info = (MYSQLND_INFILE_INFO *)ptr;
00133 
00134        if (info) {
00135               /* php_stream_close segfaults on NULL */
00136               if (info->fd) {
00137                      php_stream_close(info->fd);
00138                      info->fd = NULL;
00139               }
00140               mnd_efree(info);
00141        }
00142 }
00143 /* }}} */
00144 
00145 
00146 /* {{{ mysqlnd_local_infile_default */
00147 PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn)
00148 {
00149        conn->infile.local_infile_init = mysqlnd_local_infile_init;
00150        conn->infile.local_infile_read = mysqlnd_local_infile_read;
00151        conn->infile.local_infile_error = mysqlnd_local_infile_error;
00152        conn->infile.local_infile_end = mysqlnd_local_infile_end;
00153 }
00154 /* }}} */
00155 
00156 /* {{{ mysqlnd_set_local_infile_handler */
00157 PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname)
00158 {
00159        if (!conn->infile.callback) {
00160               MAKE_STD_ZVAL(conn->infile.callback);
00161        } else {
00162               zval_dtor(conn->infile.callback);
00163        }
00164        ZVAL_STRING(conn->infile.callback, (char*) funcname, 1);
00165 }
00166 /* }}} */
00167 
00168 
00169 static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of local file";
00170 
00171 
00172 /* {{{ mysqlnd_handle_local_infile */
00173 enum_func_status
00174 mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC)
00175 {
00176        char                        *buf = NULL;
00177        char                        empty_packet[MYSQLND_HEADER_SIZE];
00178        enum_func_status     result = FAIL;
00179        unsigned int         buflen = 4096;
00180        void                        *info = NULL;
00181        int                                bufsize;
00182        size_t                      ret;
00183        MYSQLND_INFILE              infile;
00184 
00185        DBG_ENTER("mysqlnd_handle_local_infile");
00186 
00187        if (!(conn->options.flags & CLIENT_LOCAL_FILES)) {
00188               php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
00189               /* write empty packet to server */
00190               ret = conn->net->m.send(conn, empty_packet, 0 TSRMLS_CC);
00191               *is_warning = TRUE;
00192               goto infile_error;
00193        }
00194 
00195        infile = conn->infile;
00196        /* allocate buffer for reading data */
00197        buf = (char *)mnd_ecalloc(1, buflen);
00198 
00199        *is_warning = FALSE;
00200 
00201        /* init handler: allocate read buffer and open file */
00202        if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
00203               *is_warning = TRUE;
00204               /* error occured */
00205               strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
00206               conn->error_info.error_no =
00207                             infile.local_infile_error(info, conn->error_info.error, sizeof(conn->error_info.error) TSRMLS_CC);
00208               /* write empty packet to server */
00209               ret = conn->net->m.send(conn, empty_packet, 0 TSRMLS_CC);
00210               goto infile_error;
00211        }
00212 
00213        /* read data */
00214        while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE, buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
00215               if ((ret = conn->net->m.send(conn, buf, bufsize TSRMLS_CC)) == 0) {
00216                      DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
00217                      SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
00218                      goto infile_error;
00219               }
00220        }
00221 
00222        /* send empty packet for eof */
00223        if ((ret = conn->net->m.send(conn, empty_packet, 0 TSRMLS_CC)) == 0) {
00224               SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
00225               goto infile_error;
00226        }
00227 
00228        /* error during read occured */
00229        if (bufsize < 0) {
00230               *is_warning = TRUE;
00231               DBG_ERR_FMT("Bufsize < 0, warning,  %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
00232               strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
00233               conn->error_info.error_no =
00234                             infile.local_infile_error(info, conn->error_info.error, sizeof(conn->error_info.error) TSRMLS_CC);
00235               goto infile_error;
00236        }
00237 
00238        result = PASS;
00239 
00240 infile_error:
00241        /* get response from server and update upsert values */
00242        if (FAIL == conn->m->simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY, FALSE TSRMLS_CC)) {
00243               result = FAIL;
00244        }
00245 
00246        (*conn->infile.local_infile_end)(info TSRMLS_CC);
00247        if (buf) {
00248               mnd_efree(buf);
00249        }
00250        DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
00251        DBG_RETURN(result);
00252 }
00253 /* }}} */
00254 
00255 /*
00256  * Local variables:
00257  * tab-width: 4
00258  * c-basic-offset: 4
00259  * End:
00260  * vim600: noet sw=4 ts=4 fdm=marker
00261  * vim<600: noet sw=4 ts=4
00262  */