return 0;
}
-
-static php_stream_wrapper_ops ftp_stream_wops = {
- php_stream_url_wrap_ftp,
- php_stream_ftp_stream_close, /* stream_close */
- php_stream_ftp_stream_stat,
- NULL, /* stat_url */
- NULL, /* opendir */
- "FTP"
-};
-
-PHPAPI php_stream_wrapper php_stream_ftp_wrapper = {
- &ftp_stream_wops,
- NULL,
- 1 /* is_url */
-};
-
-
-/* {{{ php_fopen_url_wrap_ftp
+/* {{{ php_ftp_fopen_connect
*/
-php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context,
+ php_stream **preuseid, php_url **presource, int *puse_ssl, int *puse_ssl_on_data
+ STREAMS_DC TSRMLS_DC)
{
- php_stream *stream=NULL, *datastream=NULL;
- php_url *resource=NULL;
- char tmp_line[512];
- char ip[sizeof("123.123.123.123")];
- unsigned short portno;
+ php_stream *stream = NULL, *reuseid = NULL;
+ php_url *resource = NULL;
+ int result, use_ssl, use_ssl_on_data = 0;
char *scratch;
- int result;
- int i, use_ssl;
- int use_ssl_on_data=0;
- php_stream *reuseid=NULL;
- char *tpath, *ttpath, *hoststart=NULL;
- size_t file_size = 0;
- zval **tmpzval;
- int allow_overwrite = 0;
-
- tmp_line[0] = '\0';
+ char tmp_line[512];
- if (strpbrk(mode, "a+")) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP does not support simultaneous read/write connections.");
- return NULL;
- }
-
resource = php_url_parse((char *) path);
if (resource == NULL || resource->path == NULL)
return NULL;
stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, NULL, 0);
if (stream == NULL) {
result = 0; /* silence */
- goto errexit;
+ goto connect_errexit;
}
php_stream_context_set(stream, context);
result = GET_FTP_RESULT(stream);
if (result > 299 || result < 200) {
php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
- goto errexit;
+ goto connect_errexit;
}
if (use_ssl) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
php_stream_close(stream);
stream = NULL;
- goto errexit;
+ goto connect_errexit;
}
/* set PBSZ to 0 */
php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
}
}
- if (result > 299 || result < 200)
- goto errexit;
+ if (result > 299 || result < 200) {
+ goto connect_errexit;
+ }
+
+ if (puse_ssl) {
+ *puse_ssl = use_ssl;
+ }
+ if (puse_ssl_on_data) {
+ *puse_ssl_on_data = use_ssl_on_data;
+ }
+ if (preuseid) {
+ *preuseid = reuseid;
+ }
+ if (presource) {
+ *presource = resource;
+ }
+
+ return stream;
+
+ connect_errexit:
+ if (stream) {
+ php_stream_close(stream);
+ }
+
+ return NULL;
+}
+/* }}} */
+
+/* {{{ php_fopen_do_pasv
+ */
+static unsigned short php_fopen_do_pasv(php_stream *stream, char *ip, int ip_size, char **phoststart STREAMS_DC TSRMLS_DC)
+{
+ char tmp_line[512];
+ int result, i;
+ unsigned short portno;
+ char *tpath, *ttpath, *hoststart=NULL;
+
+ /* We try EPSV first, needed for IPv6 and works on some IPv4 servers */
+ php_stream_write_string(stream, "EPSV\r\n");
+ result = GET_FTP_RESULT(stream);
+
+ /* check if we got a 229 response */
+ if (result != 229) {
+ /* EPSV failed, let's try PASV */
+ php_stream_write_string(stream, "PASV\r\n");
+ result = GET_FTP_RESULT(stream);
+
+ /* make sure we got a 227 response */
+ if (result != 227) {
+ return 0;
+ }
+
+ /* parse pasv command (129, 80, 95, 25, 13, 221) */
+ tpath = tmp_line;
+ /* skip over the "227 Some message " part */
+ for (tpath += 4; *tpath && !isdigit((int) *tpath); tpath++);
+ if (!*tpath) {
+ return 0;
+ }
+ /* skip over the host ip, to get the port */
+ hoststart = tpath;
+ for (i = 0; i < 4; i++) {
+ for (; isdigit((int) *tpath); tpath++);
+ if (*tpath != ',') {
+ return 0;
+ }
+ *tpath='.';
+ tpath++;
+ }
+ tpath[-1] = '\0';
+ memcpy(ip, hoststart, ip_size);
+ ip[ip_size-1] = '\0';
+ hoststart = ip;
+
+ /* pull out the MSB of the port */
+ portno = (unsigned short) strtoul(tpath, &ttpath, 10) * 256;
+ if (ttpath == NULL) {
+ /* didn't get correct response from PASV */
+ return 0;
+ }
+ tpath = ttpath;
+ if (*tpath != ',') {
+ return 0;
+ }
+ tpath++;
+ /* pull out the LSB of the port */
+ portno += (unsigned short) strtoul(tpath, &ttpath, 10);
+ } else {
+ /* parse epsv command (|||6446|) */
+ for (i = 0, tpath = tmp_line + 4; *tpath; tpath++) {
+ if (*tpath == '|') {
+ i++;
+ if (i == 3)
+ break;
+ }
+ }
+ if (i < 3) {
+ return 0;
+ }
+ /* pull out the port */
+ portno = (unsigned short) strtoul(tpath + 1, &ttpath, 10);
+ }
+ if (ttpath == NULL) {
+ /* didn't get correct response from EPSV/PASV */
+ return 0;
+ }
+
+ if (phoststart) {
+ *phoststart = hoststart;
+ }
+
+ return portno;
+}
+/* }}} */
+
+/* {{{ php_fopen_url_wrap_ftp
+ */
+php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = NULL, *datastream = NULL;
+ php_url *resource = NULL;
+ char tmp_line[512];
+ char ip[sizeof("123.123.123.123")];
+ unsigned short portno;
+ char *scratch, *hoststart = NULL;
+ int result, use_ssl, use_ssl_on_data=0;
+ php_stream *reuseid=NULL;
+ size_t file_size = 0;
+ zval **tmpzval;
+ int allow_overwrite = 0;
+
+ tmp_line[0] = '\0';
+
+ if (strpbrk(mode, "a+")) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP does not support simultaneous read/write connections.");
+ return NULL;
+ }
+
+ stream = php_ftp_fopen_connect(wrapper, path, mode, options, opened_path, context, &reuseid, &resource, &use_ssl, &use_ssl_on_data STREAMS_CC TSRMLS_CC);
+
/* set the connection to be binary */
php_stream_write_string(stream, "TYPE I\r\n");
result = GET_FTP_RESULT(stream);
}
/* set up the passive connection */
+ portno = php_fopen_do_pasv(stream, ip, sizeof(ip), &hoststart STREAMS_CC TSRMLS_CC);
- /* We try EPSV first, needed for IPv6 and works on some IPv4 servers */
- php_stream_write_string(stream, "EPSV\r\n");
- result = GET_FTP_RESULT(stream);
-
- /* check if we got a 229 response */
- if (result != 229) {
- /* EPSV failed, let's try PASV */
- php_stream_write_string(stream, "PASV\r\n");
- result = GET_FTP_RESULT(stream);
-
- /* make sure we got a 227 response */
- if (result != 227)
- goto errexit;
-
- /* parse pasv command (129, 80, 95, 25, 13, 221) */
- tpath = tmp_line;
- /* skip over the "227 Some message " part */
- for (tpath += 4; *tpath && !isdigit((int) *tpath); tpath++);
- if (!*tpath)
- goto errexit;
- /* skip over the host ip, to get the port */
- hoststart = tpath;
- for (i = 0; i < 4; i++) {
- for (; isdigit((int) *tpath); tpath++);
- if (*tpath != ',')
- goto errexit;
- *tpath='.';
- tpath++;
- }
- tpath[-1] = '\0';
- memcpy(ip, hoststart, sizeof(ip));
- ip[sizeof(ip)-1] = '\0';
- hoststart = ip;
-
- /* pull out the MSB of the port */
- portno = (unsigned short) strtoul(tpath, &ttpath, 10) * 256;
- if (ttpath == NULL) {
- /* didn't get correct response from PASV */
- goto errexit;
- }
- tpath = ttpath;
- if (*tpath != ',')
- goto errexit;
- tpath++;
- /* pull out the LSB of the port */
- portno += (unsigned short) strtoul(tpath, &ttpath, 10);
- } else {
- /* parse epsv command (|||6446|) */
- for (i = 0, tpath = tmp_line + 4; *tpath; tpath++) {
- if (*tpath == '|') {
- i++;
- if (i == 3)
- break;
- }
- }
- if (i < 3)
- goto errexit;
- /* pull out the port */
- portno = (unsigned short) strtoul(tpath + 1, &ttpath, 10);
- }
-
- if (ttpath == NULL) {
- /* didn't get correct response from EPSV/PASV */
+ if (!portno) {
goto errexit;
}
-
+
+ /* Send RETR/STOR command */
if (mode[0] == 'r') {
/* retrieve file */
php_stream_write_string(stream, "RETR ");
}
/* }}} */
+/* {{{ php_ftp_dirsteam_read
+ */
+static size_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_stream_dirent *ent = (php_stream_dirent *)buf;
+ php_stream *innerstream = (php_stream *)stream->abstract;
+ size_t tmp_len;
+ char *basename;
+
+ if (count != sizeof(php_stream_dirent)) {
+ return 0;
+ }
+
+ if (php_stream_eof(innerstream)) {
+ return 0;
+ }
+
+ if (!php_stream_get_line(innerstream, ent->d_name, sizeof(ent->d_name), &tmp_len)) {
+ return 0;
+ }
+ if (!(basename = php_basename(ent->d_name, tmp_len, NULL, 0))) {
+ return 0;
+ }
+
+ if (strlen(basename) == 0) {
+ efree(basename);
+ return 0;
+ }
+ strcpy(ent->d_name, basename);
+ efree(basename);
+
+ return sizeof(php_stream_dirent);
+}
+/* }}} */
+
+/* {{{ php_ftp_dirstream_close
+ */
+static int php_ftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_stream *innerstream = (php_stream *)stream->abstract;
+
+ if (innerstream->wrapperdata) {
+ php_stream_close((php_stream *)innerstream->wrapperdata);
+ innerstream->wrapperdata = NULL;
+ }
+ php_stream_close((php_stream *)stream->abstract);
+ stream->abstract = NULL;
+
+ return 0;
+}
+/* }}} */
+
+/* ftp dirstreams only need to support read and close operations,
+ They can't be rewound because the underlying ftp stream can't be rewound. */
+static php_stream_ops php_ftp_dirstream_ops = {
+ NULL, /* write */
+ php_ftp_dirstream_read, /* read */
+ php_ftp_dirstream_close, /* close */
+ NULL, /* flush */
+ "ftpdir",
+ NULL, /* rewind */
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL /* set option */
+};
+
+/* {{{ php_stream_ftp_opendir
+ */
+php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream, *reuseid, *datastream = NULL;
+ php_url *resource;
+ int result, use_ssl, use_ssl_on_data = 0;
+ char *hoststart = NULL, tmp_line[512];
+ char ip[sizeof("123.123.123.123")];
+ unsigned short portno;
+
+ stream = php_ftp_fopen_connect(wrapper, path, mode, options, opened_path, context, &reuseid, &resource, &use_ssl, &use_ssl_on_data STREAMS_CC TSRMLS_CC);
+
+ /* set the connection to be ascii */
+ php_stream_write_string(stream, "TYPE A\r\n");
+ result = GET_FTP_RESULT(stream);
+ if (result > 299 || result < 200)
+ goto opendir_errexit;
+
+ /* set up the passive connection */
+ portno = php_fopen_do_pasv(stream, ip, sizeof(ip), &hoststart STREAMS_CC TSRMLS_CC);
+
+ if (!portno) {
+ goto opendir_errexit;
+ }
+
+ php_stream_write_string(stream, "NLST ");
+ if (resource->path != NULL) {
+ php_stream_write_string(stream, resource->path);
+ } else {
+ php_stream_write_string(stream, "/");
+ }
+ php_stream_write_string(stream, "\r\n");
+
+ /* open the data channel */
+ if (hoststart == NULL) {
+ hoststart = resource->host;
+ }
+ datastream = php_stream_sock_open_host(hoststart, portno, SOCK_STREAM, 0, 0);
+ if (datastream == NULL) {
+ goto opendir_errexit;
+ }
+
+ result = GET_FTP_RESULT(stream);
+ if (result != 150 && result != 125) {
+ /* Could not retrieve or send the file
+ * this data will only be sent to us after connection on the data port was initiated.
+ */
+ php_stream_close(datastream);
+ datastream = NULL;
+ goto opendir_errexit;
+ }
+
+ /* close control connection if not in ssl mode */
+ if (!use_ssl) {
+ php_stream_write_string(stream, "QUIT\r\n");
+ php_stream_close(stream);
+ stream = NULL;
+ }
+
+ php_stream_context_set(datastream, context);
+
+ if (use_ssl_on_data && (php_stream_xport_crypto_setup(stream,
+ STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
+ php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0)) {
+
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
+ php_stream_close(datastream);
+ datastream = NULL;
+ goto opendir_errexit;
+ }
+
+ /* remember control stream */
+ datastream->wrapperdata = (zval *)stream;
+
+ php_url_free(resource);
+ return php_stream_alloc(&php_ftp_dirstream_ops, datastream, 0, mode);
+
+ opendir_errexit:
+ php_url_free(resource);
+ if (stream) {
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
+ php_stream_close(stream);
+ }
+ if (tmp_line[0] != '\0')
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP server reports %s", tmp_line);
+ return NULL;
+}
+/* }}} */
+
+static php_stream_wrapper_ops ftp_stream_wops = {
+ php_stream_url_wrap_ftp,
+ php_stream_ftp_stream_close, /* stream_close */
+ php_stream_ftp_stream_stat,
+ NULL, /* stat_url */
+ php_stream_ftp_opendir, /* opendir */
+ "FTP"
+};
+
+PHPAPI php_stream_wrapper php_stream_ftp_wrapper = {
+ &ftp_stream_wops,
+ NULL,
+ 1 /* is_url */
+};
+
+
/*
* Local variables:
* tab-width: 4