1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 2006-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Georg Richter <georg@mysql.com> |
16 : | Andrey Hristov <andrey@mysql.com> |
17 : | Ulf Wendel <uwendel@mysql.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : #include "php.h"
22 : #include "php_globals.h"
23 : #include "mysqlnd.h"
24 : #include "mysqlnd_wireprotocol.h"
25 : #include "mysqlnd_priv.h"
26 : #include "mysqlnd_debug.h"
27 :
28 : enum_func_status mysqlnd_simple_command_handle_response(MYSQLND *conn,
29 : enum php_mysql_packet_type ok_packet,
30 : zend_bool silent, enum php_mysqlnd_server_command command,
31 : zend_bool ignore_upsert_status
32 : TSRMLS_DC);
33 :
34 :
35 : #define ALLOC_CALLBACK_ARGS(a, b, c)\
36 : if (c) {\
37 : a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
38 : for (i = b; i < c; i++) {\
39 : a[i] = mnd_emalloc(sizeof(zval *));\
40 : MAKE_STD_ZVAL(*a[i]);\
41 : }\
42 : }
43 :
44 : #define FREE_CALLBACK_ARGS(a, b, c)\
45 : if (a) {\
46 : for (i=b; i < c; i++) {\
47 : zval_ptr_dtor(a[i]);\
48 : mnd_efree(a[i]);\
49 : }\
50 : mnd_efree(a);\
51 : }
52 :
53 : /* {{{ mysqlnd_local_infile_init */
54 : static
55 : int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS_DC)
56 6 : {
57 : MYSQLND_INFILE_INFO *info;
58 6 : php_stream_context *context = NULL;
59 :
60 6 : DBG_ENTER("mysqlnd_local_infile_init");
61 :
62 6 : *ptr = info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
63 :
64 : /* check open_basedir */
65 6 : if (PG(open_basedir)) {
66 6 : if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
67 0 : strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
68 0 : info->error_no = CR_UNKNOWN_ERROR;
69 0 : DBG_RETURN(1);
70 : }
71 : }
72 :
73 6 : info->filename = filename;
74 6 : info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
75 :
76 6 : if (info->fd == NULL) {
77 1 : snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
78 1 : info->error_no = MYSQLND_EE_FILENOTFOUND;
79 1 : DBG_RETURN(1);
80 : }
81 :
82 5 : DBG_RETURN(0);
83 : }
84 : /* }}} */
85 :
86 :
87 : /* {{{ mysqlnd_local_infile_read */
88 : static
89 : int mysqlnd_local_infile_read(void *ptr, char *buf, unsigned int buf_len TSRMLS_DC)
90 387 : {
91 387 : MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
92 : int count;
93 :
94 387 : DBG_ENTER("mysqlnd_local_infile_read");
95 :
96 387 : count = (int)php_stream_read(info->fd, buf, buf_len);
97 :
98 387 : if (count < 0) {
99 0 : strcpy(info->error_msg, "Error reading file");
100 0 : info->error_no = CR_UNKNOWN_ERROR;
101 : }
102 :
103 387 : DBG_RETURN(count);
104 : }
105 : /* }}} */
106 :
107 :
108 : /* {{{ mysqlnd_local_infile_error */
109 : static
110 : int mysqlnd_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len TSRMLS_DC)
111 1 : {
112 1 : MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
113 :
114 1 : DBG_ENTER("mysqlnd_local_infile_error");
115 :
116 1 : if (info) {
117 1 : strlcpy(error_buf, info->error_msg, error_buf_len);
118 1 : DBG_INF_FMT("have info, %d", info->error_no);
119 1 : DBG_RETURN(info->error_no);
120 : }
121 :
122 0 : strlcpy(error_buf, "Unknown error", error_buf_len);
123 0 : DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
124 0 : DBG_RETURN(CR_UNKNOWN_ERROR);
125 : }
126 : /* }}} */
127 :
128 :
129 : /* {{{ mysqlnd_local_infile_end */
130 : static
131 : void mysqlnd_local_infile_end(void *ptr TSRMLS_DC)
132 6 : {
133 6 : MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
134 :
135 6 : if (info) {
136 : /* php_stream_close segfaults on NULL */
137 6 : if (info->fd) {
138 5 : php_stream_close(info->fd);
139 5 : info->fd = NULL;
140 : }
141 6 : mnd_efree(info);
142 : }
143 6 : }
144 : /* }}} */
145 :
146 :
147 : /* {{{ mysqlnd_local_infile_default */
148 : PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn)
149 3366 : {
150 3366 : conn->infile.local_infile_init = mysqlnd_local_infile_init;
151 3366 : conn->infile.local_infile_read = mysqlnd_local_infile_read;
152 3366 : conn->infile.local_infile_error = mysqlnd_local_infile_error;
153 3366 : conn->infile.local_infile_end = mysqlnd_local_infile_end;
154 3366 : }
155 : /* }}} */
156 :
157 : /* {{{ mysqlnd_set_local_infile_handler */
158 : PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname)
159 0 : {
160 0 : if (!conn->infile.callback) {
161 0 : MAKE_STD_ZVAL(conn->infile.callback);
162 : } else {
163 0 : zval_dtor(conn->infile.callback);
164 : }
165 0 : ZVAL_STRING(conn->infile.callback, (char*) funcname, 1);
166 0 : }
167 : /* }}} */
168 :
169 :
170 : static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of local file";
171 :
172 :
173 : /* {{{ mysqlnd_handle_local_infile */
174 : enum_func_status
175 : mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC)
176 6 : {
177 : char *buf;
178 : char empty_packet[MYSQLND_HEADER_SIZE];
179 6 : enum_func_status result = FAIL;
180 6 : unsigned int buflen = 4096;
181 6 : void *info = NULL;
182 : int bufsize;
183 : size_t ret;
184 : MYSQLND_INFILE infile;
185 :
186 6 : DBG_ENTER("mysqlnd_handle_local_infile");
187 :
188 6 : if (!(conn->options.flags & CLIENT_LOCAL_FILES)) {
189 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
190 : /* write empty packet to server */
191 0 : ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
192 0 : *is_warning = TRUE;
193 0 : goto infile_error;
194 : }
195 :
196 6 : infile = conn->infile;
197 : /* allocate buffer for reading data */
198 6 : buf = (char *)mnd_ecalloc(1, buflen);
199 :
200 6 : *is_warning = FALSE;
201 :
202 : /* init handler: allocate read buffer and open file */
203 6 : if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
204 1 : *is_warning = TRUE;
205 : /* error occured */
206 1 : strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
207 1 : conn->error_info.error_no =
208 : infile.local_infile_error(info, conn->error_info.error,
209 : sizeof(conn->error_info.error) TSRMLS_CC);
210 : /* write empty packet to server */
211 1 : ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
212 1 : goto infile_error;
213 : }
214 :
215 : /* read data */
216 392 : while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE,
217 : buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
218 382 : if ((ret = mysqlnd_stream_write_w_header(conn, buf, bufsize TSRMLS_CC)) < 0) {
219 : DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
220 : SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
221 : goto infile_error;
222 : }
223 : }
224 :
225 : /* send empty packet for eof */
226 5 : if ((ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC)) < 0) {
227 : SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
228 : goto infile_error;
229 : }
230 :
231 : /* error during read occured */
232 5 : if (bufsize < 0) {
233 0 : *is_warning = TRUE;
234 0 : DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
235 0 : strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
236 0 : conn->error_info.error_no = infile.local_infile_error(info, conn->error_info.error,
237 : sizeof(conn->error_info.error) TSRMLS_CC);
238 0 : goto infile_error;
239 : }
240 :
241 5 : result = PASS;
242 :
243 6 : infile_error:
244 : /* get response from server and update upsert values */
245 6 : if (FAIL == mysqlnd_simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY, FALSE TSRMLS_CC)) {
246 0 : result = FAIL;
247 : }
248 :
249 6 : (*conn->infile.local_infile_end)(info TSRMLS_CC);
250 6 : mnd_efree(buf);
251 6 : DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
252 6 : DBG_RETURN(result);
253 : }
254 : /* }}} */
255 :
256 : /*
257 : * Local variables:
258 : * tab-width: 4
259 : * c-basic-offset: 4
260 : * End:
261 : * vim600: noet sw=4 ts=4 fdm=marker
262 : * vim<600: noet sw=4 ts=4
263 : */
|