mysqlnd_loaddata.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-2016 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: Andrey Hristov <andrey@mysql.com> |
  16. | Ulf Wendel <uwendel@mysql.com> |
  17. | Georg Richter <georg@mysql.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #include "php.h"
  21. #include "php_globals.h"
  22. #include "mysqlnd.h"
  23. #include "mysqlnd_wireprotocol.h"
  24. #include "mysqlnd_priv.h"
  25. #include "mysqlnd_debug.h"
  26. /* {{{ mysqlnd_local_infile_init */
  27. static
  28. int mysqlnd_local_infile_init(void ** ptr, char * filename, void ** userdata TSRMLS_DC)
  29. {
  30. MYSQLND_INFILE_INFO *info;
  31. php_stream_context *context = NULL;
  32. DBG_ENTER("mysqlnd_local_infile_init");
  33. info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
  34. if (!info) {
  35. DBG_RETURN(1);
  36. }
  37. *ptr = info;
  38. /* check open_basedir */
  39. if (PG(open_basedir)) {
  40. if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
  41. strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
  42. info->error_no = CR_UNKNOWN_ERROR;
  43. DBG_RETURN(1);
  44. }
  45. }
  46. info->filename = filename;
  47. info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
  48. if (info->fd == NULL) {
  49. snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
  50. info->error_no = MYSQLND_EE_FILENOTFOUND;
  51. DBG_RETURN(1);
  52. }
  53. DBG_RETURN(0);
  54. }
  55. /* }}} */
  56. /* {{{ mysqlnd_local_infile_read */
  57. static
  58. int mysqlnd_local_infile_read(void * ptr, zend_uchar * buf, unsigned int buf_len TSRMLS_DC)
  59. {
  60. MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
  61. int count;
  62. DBG_ENTER("mysqlnd_local_infile_read");
  63. count = (int)php_stream_read(info->fd, (char *) buf, buf_len);
  64. if (count < 0) {
  65. strcpy(info->error_msg, "Error reading file");
  66. info->error_no = CR_UNKNOWN_ERROR;
  67. }
  68. DBG_RETURN(count);
  69. }
  70. /* }}} */
  71. /* {{{ mysqlnd_local_infile_error */
  72. static
  73. int mysqlnd_local_infile_error(void * ptr, char *error_buf, unsigned int error_buf_len TSRMLS_DC)
  74. {
  75. MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
  76. DBG_ENTER("mysqlnd_local_infile_error");
  77. if (info) {
  78. strlcpy(error_buf, info->error_msg, error_buf_len);
  79. DBG_INF_FMT("have info, %d", info->error_no);
  80. DBG_RETURN(info->error_no);
  81. }
  82. strlcpy(error_buf, "Unknown error", error_buf_len);
  83. DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
  84. DBG_RETURN(CR_UNKNOWN_ERROR);
  85. }
  86. /* }}} */
  87. /* {{{ mysqlnd_local_infile_end */
  88. static
  89. void mysqlnd_local_infile_end(void * ptr TSRMLS_DC)
  90. {
  91. MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
  92. if (info) {
  93. /* php_stream_close segfaults on NULL */
  94. if (info->fd) {
  95. php_stream_close(info->fd);
  96. info->fd = NULL;
  97. }
  98. mnd_efree(info);
  99. }
  100. }
  101. /* }}} */
  102. /* {{{ mysqlnd_local_infile_default */
  103. PHPAPI void
  104. mysqlnd_local_infile_default(MYSQLND_CONN_DATA * conn)
  105. {
  106. conn->infile.local_infile_init = mysqlnd_local_infile_init;
  107. conn->infile.local_infile_read = mysqlnd_local_infile_read;
  108. conn->infile.local_infile_error = mysqlnd_local_infile_error;
  109. conn->infile.local_infile_end = mysqlnd_local_infile_end;
  110. }
  111. /* }}} */
  112. /* {{{ mysqlnd_set_local_infile_handler */
  113. PHPAPI void
  114. mysqlnd_set_local_infile_handler(MYSQLND_CONN_DATA * const conn, const char * const funcname)
  115. {
  116. if (!conn->infile.callback) {
  117. MAKE_STD_ZVAL(conn->infile.callback);
  118. } else {
  119. zval_dtor(conn->infile.callback);
  120. }
  121. ZVAL_STRING(conn->infile.callback, (char*) funcname, 1);
  122. }
  123. /* }}} */
  124. static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of local file";
  125. /* {{{ mysqlnd_handle_local_infile */
  126. enum_func_status
  127. mysqlnd_handle_local_infile(MYSQLND_CONN_DATA * conn, const char * filename, zend_bool * is_warning TSRMLS_DC)
  128. {
  129. zend_uchar *buf = NULL;
  130. zend_uchar empty_packet[MYSQLND_HEADER_SIZE];
  131. enum_func_status result = FAIL;
  132. unsigned int buflen = 4096;
  133. void *info = NULL;
  134. int bufsize;
  135. size_t ret;
  136. MYSQLND_INFILE infile;
  137. MYSQLND_NET * net = conn->net;
  138. DBG_ENTER("mysqlnd_handle_local_infile");
  139. if (!(conn->options->flags & CLIENT_LOCAL_FILES)) {
  140. php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
  141. /* write empty packet to server */
  142. ret = net->data->m.send_ex(net, empty_packet, 0, conn->stats, conn->error_info TSRMLS_CC);
  143. *is_warning = TRUE;
  144. goto infile_error;
  145. }
  146. infile = conn->infile;
  147. /* allocate buffer for reading data */
  148. buf = (zend_uchar *) mnd_ecalloc(1, buflen);
  149. *is_warning = FALSE;
  150. /* init handler: allocate read buffer and open file */
  151. if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
  152. char tmp_buf[sizeof(conn->error_info->error)];
  153. int tmp_error_no;
  154. *is_warning = TRUE;
  155. /* error occurred */
  156. tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf) TSRMLS_CC);
  157. SET_CLIENT_ERROR(*conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
  158. /* write empty packet to server */
  159. ret = net->data->m.send_ex(net, empty_packet, 0, conn->stats, conn->error_info TSRMLS_CC);
  160. goto infile_error;
  161. }
  162. /* read data */
  163. while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE, buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
  164. if ((ret = net->data->m.send_ex(net, buf, bufsize, conn->stats, conn->error_info TSRMLS_CC)) == 0) {
  165. DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
  166. SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
  167. goto infile_error;
  168. }
  169. }
  170. /* send empty packet for eof */
  171. if ((ret = net->data->m.send_ex(net, empty_packet, 0, conn->stats, conn->error_info TSRMLS_CC)) == 0) {
  172. SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
  173. goto infile_error;
  174. }
  175. /* error during read occurred */
  176. if (bufsize < 0) {
  177. char tmp_buf[sizeof(conn->error_info->error)];
  178. int tmp_error_no;
  179. *is_warning = TRUE;
  180. DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
  181. tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf) TSRMLS_CC);
  182. SET_CLIENT_ERROR(*conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
  183. goto infile_error;
  184. }
  185. result = PASS;
  186. infile_error:
  187. /* get response from server and update upsert values */
  188. if (FAIL == conn->m->simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY, FALSE TSRMLS_CC)) {
  189. result = FAIL;
  190. }
  191. (*conn->infile.local_infile_end)(info TSRMLS_CC);
  192. if (buf) {
  193. mnd_efree(buf);
  194. }
  195. DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
  196. DBG_RETURN(result);
  197. }
  198. /* }}} */
  199. /*
  200. * Local variables:
  201. * tab-width: 4
  202. * c-basic-offset: 4
  203. * End:
  204. * vim600: noet sw=4 ts=4 fdm=marker
  205. * vim<600: noet sw=4 ts=4
  206. */