1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 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: Andrew Skalski <askalski@chek.com>                          |
16    |          Stefan Esser <sesser@php.net> (resume functions)            |
17    +----------------------------------------------------------------------+
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "php.h"
25 
26 #ifdef HAVE_FTP_SSL
27 # include <openssl/ssl.h>
28 #endif
29 
30 #if HAVE_FTP
31 
32 #include "ext/standard/info.h"
33 #include "ext/standard/file.h"
34 
35 #include "php_ftp.h"
36 #include "ftp.h"
37 
38 static int le_ftpbuf;
39 #define le_ftpbuf_name "FTP Buffer"
40 
41 /* {{{ arginfo */
42 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_connect, 0, 0, 1)
43 	ZEND_ARG_INFO(0, host)
44 	ZEND_ARG_INFO(0, port)
45 	ZEND_ARG_INFO(0, timeout)
46 ZEND_END_ARG_INFO()
47 
48 #ifdef HAVE_FTP_SSL
49 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_ssl_connect, 0, 0, 1)
50 	ZEND_ARG_INFO(0, host)
51 	ZEND_ARG_INFO(0, port)
52 	ZEND_ARG_INFO(0, timeout)
53 ZEND_END_ARG_INFO()
54 #endif
55 
56 ZEND_BEGIN_ARG_INFO(arginfo_ftp_login, 0)
57 	ZEND_ARG_INFO(0, ftp)
58 	ZEND_ARG_INFO(0, username)
59 	ZEND_ARG_INFO(0, password)
60 ZEND_END_ARG_INFO()
61 
62 ZEND_BEGIN_ARG_INFO(arginfo_ftp_pwd, 0)
63 	ZEND_ARG_INFO(0, ftp)
64 ZEND_END_ARG_INFO()
65 
66 ZEND_BEGIN_ARG_INFO(arginfo_ftp_cdup, 0)
67 	ZEND_ARG_INFO(0, ftp)
68 ZEND_END_ARG_INFO()
69 
70 ZEND_BEGIN_ARG_INFO(arginfo_ftp_chdir, 0)
71 	ZEND_ARG_INFO(0, ftp)
72 	ZEND_ARG_INFO(0, directory)
73 ZEND_END_ARG_INFO()
74 
75 ZEND_BEGIN_ARG_INFO(arginfo_ftp_exec, 0)
76 	ZEND_ARG_INFO(0, ftp)
77 	ZEND_ARG_INFO(0, command)
78 ZEND_END_ARG_INFO()
79 
80 ZEND_BEGIN_ARG_INFO(arginfo_ftp_raw, 0)
81 	ZEND_ARG_INFO(0, ftp)
82 	ZEND_ARG_INFO(0, command)
83 ZEND_END_ARG_INFO()
84 
85 ZEND_BEGIN_ARG_INFO(arginfo_ftp_mkdir, 0)
86 	ZEND_ARG_INFO(0, ftp)
87 	ZEND_ARG_INFO(0, directory)
88 ZEND_END_ARG_INFO()
89 
90 ZEND_BEGIN_ARG_INFO(arginfo_ftp_rmdir, 0)
91 	ZEND_ARG_INFO(0, ftp)
92 	ZEND_ARG_INFO(0, directory)
93 ZEND_END_ARG_INFO()
94 
95 ZEND_BEGIN_ARG_INFO(arginfo_ftp_chmod, 0)
96 	ZEND_ARG_INFO(0, ftp)
97 	ZEND_ARG_INFO(0, mode)
98 	ZEND_ARG_INFO(0, filename)
99 ZEND_END_ARG_INFO()
100 
101 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_alloc, 0, 0, 2)
102 	ZEND_ARG_INFO(0, ftp)
103 	ZEND_ARG_INFO(0, size)
104 	ZEND_ARG_INFO(1, response)
105 ZEND_END_ARG_INFO()
106 
107 ZEND_BEGIN_ARG_INFO(arginfo_ftp_nlist, 0)
108 	ZEND_ARG_INFO(0, ftp)
109 	ZEND_ARG_INFO(0, directory)
110 ZEND_END_ARG_INFO()
111 
112 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_rawlist, 0, 0, 2)
113 	ZEND_ARG_INFO(0, ftp)
114 	ZEND_ARG_INFO(0, directory)
115 	ZEND_ARG_INFO(0, recursive)
116 ZEND_END_ARG_INFO()
117 
118 ZEND_BEGIN_ARG_INFO(arginfo_ftp_mlsd, 0)
119 	ZEND_ARG_INFO(0, ftp)
120 	ZEND_ARG_INFO(0, directory)
121 ZEND_END_ARG_INFO()
122 
123 ZEND_BEGIN_ARG_INFO(arginfo_ftp_systype, 0)
124 	ZEND_ARG_INFO(0, ftp)
125 ZEND_END_ARG_INFO()
126 
127 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_fget, 0, 0, 3)
128 	ZEND_ARG_INFO(0, ftp)
129 	ZEND_ARG_INFO(0, fp)
130 	ZEND_ARG_INFO(0, remote_file)
131 	ZEND_ARG_INFO(0, mode)
132 	ZEND_ARG_INFO(0, resumepos)
133 ZEND_END_ARG_INFO()
134 
135 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_nb_fget, 0, 0, 3)
136 	ZEND_ARG_INFO(0, ftp)
137 	ZEND_ARG_INFO(0, fp)
138 	ZEND_ARG_INFO(0, remote_file)
139 	ZEND_ARG_INFO(0, mode)
140 	ZEND_ARG_INFO(0, resumepos)
141 ZEND_END_ARG_INFO()
142 
143 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_pasv, 0, 0, 2)
144 	ZEND_ARG_INFO(0, ftp)
145 	ZEND_ARG_INFO(0, pasv)
146 ZEND_END_ARG_INFO()
147 
148 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_get, 0, 0, 3)
149 	ZEND_ARG_INFO(0, ftp)
150 	ZEND_ARG_INFO(0, local_file)
151 	ZEND_ARG_INFO(0, remote_file)
152 	ZEND_ARG_INFO(0, mode)
153 	ZEND_ARG_INFO(0, resume_pos)
154 ZEND_END_ARG_INFO()
155 
156 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_nb_get, 0, 0, 3)
157 	ZEND_ARG_INFO(0, ftp)
158 	ZEND_ARG_INFO(0, local_file)
159 	ZEND_ARG_INFO(0, remote_file)
160 	ZEND_ARG_INFO(0, mode)
161 	ZEND_ARG_INFO(0, resume_pos)
162 ZEND_END_ARG_INFO()
163 
164 ZEND_BEGIN_ARG_INFO(arginfo_ftp_nb_continue, 0)
165 	ZEND_ARG_INFO(0, ftp)
166 ZEND_END_ARG_INFO()
167 
168 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_fput, 0, 0, 3)
169 	ZEND_ARG_INFO(0, ftp)
170 	ZEND_ARG_INFO(0, remote_file)
171 	ZEND_ARG_INFO(0, fp)
172 	ZEND_ARG_INFO(0, mode)
173 	ZEND_ARG_INFO(0, startpos)
174 ZEND_END_ARG_INFO()
175 
176 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_nb_fput, 0, 0, 3)
177 	ZEND_ARG_INFO(0, ftp)
178 	ZEND_ARG_INFO(0, remote_file)
179 	ZEND_ARG_INFO(0, fp)
180 	ZEND_ARG_INFO(0, mode)
181 	ZEND_ARG_INFO(0, startpos)
182 ZEND_END_ARG_INFO()
183 
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_put, 0, 0, 3)
185 	ZEND_ARG_INFO(0, ftp)
186 	ZEND_ARG_INFO(0, remote_file)
187 	ZEND_ARG_INFO(0, local_file)
188 	ZEND_ARG_INFO(0, mode)
189 	ZEND_ARG_INFO(0, startpos)
190 ZEND_END_ARG_INFO()
191 
192 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_append, 0, 0, 3)
193 	ZEND_ARG_INFO(0, ftp)
194 	ZEND_ARG_INFO(0, remote_file)
195 	ZEND_ARG_INFO(0, local_file)
196 	ZEND_ARG_INFO(0, mode)
197 ZEND_END_ARG_INFO()
198 
199 ZEND_BEGIN_ARG_INFO_EX(arginfo_ftp_nb_put, 0, 0, 3)
200 	ZEND_ARG_INFO(0, ftp)
201 	ZEND_ARG_INFO(0, remote_file)
202 	ZEND_ARG_INFO(0, local_file)
203 	ZEND_ARG_INFO(0, mode)
204 	ZEND_ARG_INFO(0, startpos)
205 ZEND_END_ARG_INFO()
206 
207 ZEND_BEGIN_ARG_INFO(arginfo_ftp_size, 0)
208 	ZEND_ARG_INFO(0, ftp)
209 	ZEND_ARG_INFO(0, filename)
210 ZEND_END_ARG_INFO()
211 
212 ZEND_BEGIN_ARG_INFO(arginfo_ftp_mdtm, 0)
213 	ZEND_ARG_INFO(0, ftp)
214 	ZEND_ARG_INFO(0, filename)
215 ZEND_END_ARG_INFO()
216 
217 ZEND_BEGIN_ARG_INFO(arginfo_ftp_rename, 0)
218 	ZEND_ARG_INFO(0, ftp)
219 	ZEND_ARG_INFO(0, src)
220 	ZEND_ARG_INFO(0, dest)
221 ZEND_END_ARG_INFO()
222 
223 ZEND_BEGIN_ARG_INFO(arginfo_ftp_delete, 0)
224 	ZEND_ARG_INFO(0, ftp)
225 	ZEND_ARG_INFO(0, file)
226 ZEND_END_ARG_INFO()
227 
228 ZEND_BEGIN_ARG_INFO(arginfo_ftp_site, 0)
229 	ZEND_ARG_INFO(0, ftp)
230 	ZEND_ARG_INFO(0, cmd)
231 ZEND_END_ARG_INFO()
232 
233 ZEND_BEGIN_ARG_INFO(arginfo_ftp_close, 0)
234 	ZEND_ARG_INFO(0, ftp)
235 ZEND_END_ARG_INFO()
236 
237 ZEND_BEGIN_ARG_INFO(arginfo_ftp_set_option, 0)
238 	ZEND_ARG_INFO(0, ftp)
239 	ZEND_ARG_INFO(0, option)
240 	ZEND_ARG_INFO(0, value)
241 ZEND_END_ARG_INFO()
242 
243 ZEND_BEGIN_ARG_INFO(arginfo_ftp_get_option, 0)
244 	ZEND_ARG_INFO(0, ftp)
245 	ZEND_ARG_INFO(0, option)
246 ZEND_END_ARG_INFO()
247 
248 /* }}} */
249 
250 static const zend_function_entry php_ftp_functions[] = {
251 	PHP_FE(ftp_connect,			arginfo_ftp_connect)
252 #ifdef HAVE_FTP_SSL
253 	PHP_FE(ftp_ssl_connect,		arginfo_ftp_ssl_connect)
254 #endif
255 	PHP_FE(ftp_login,			arginfo_ftp_login)
256 	PHP_FE(ftp_pwd,				arginfo_ftp_pwd)
257 	PHP_FE(ftp_cdup,			arginfo_ftp_cdup)
258 	PHP_FE(ftp_chdir,			arginfo_ftp_chdir)
259 	PHP_FE(ftp_exec,			arginfo_ftp_exec)
260 	PHP_FE(ftp_raw,				arginfo_ftp_raw)
261 	PHP_FE(ftp_mkdir,			arginfo_ftp_mkdir)
262 	PHP_FE(ftp_rmdir,			arginfo_ftp_rmdir)
263 	PHP_FE(ftp_chmod,			arginfo_ftp_chmod)
264 	PHP_FE(ftp_alloc,			arginfo_ftp_alloc)
265 	PHP_FE(ftp_nlist,			arginfo_ftp_nlist)
266 	PHP_FE(ftp_rawlist,			arginfo_ftp_rawlist)
267 	PHP_FE(ftp_mlsd,			arginfo_ftp_mlsd)
268 	PHP_FE(ftp_systype,			arginfo_ftp_systype)
269 	PHP_FE(ftp_pasv,			arginfo_ftp_pasv)
270 	PHP_FE(ftp_get,				arginfo_ftp_get)
271 	PHP_FE(ftp_fget,			arginfo_ftp_fget)
272 	PHP_FE(ftp_put,				arginfo_ftp_put)
273 	PHP_FE(ftp_append,			arginfo_ftp_append)
274 	PHP_FE(ftp_fput,			arginfo_ftp_fput)
275 	PHP_FE(ftp_size,			arginfo_ftp_size)
276 	PHP_FE(ftp_mdtm,			arginfo_ftp_mdtm)
277 	PHP_FE(ftp_rename,			arginfo_ftp_rename)
278 	PHP_FE(ftp_delete,			arginfo_ftp_delete)
279 	PHP_FE(ftp_site,			arginfo_ftp_site)
280 	PHP_FE(ftp_close,			arginfo_ftp_close)
281 	PHP_FE(ftp_set_option,		arginfo_ftp_set_option)
282 	PHP_FE(ftp_get_option,		arginfo_ftp_get_option)
283 	PHP_FE(ftp_nb_fget,			arginfo_ftp_nb_fget)
284 	PHP_FE(ftp_nb_get,			arginfo_ftp_nb_get)
285 	PHP_FE(ftp_nb_continue,		arginfo_ftp_nb_continue)
286 	PHP_FE(ftp_nb_put,			arginfo_ftp_nb_put)
287 	PHP_FE(ftp_nb_fput,			arginfo_ftp_nb_fput)
288 	PHP_FALIAS(ftp_quit, ftp_close, arginfo_ftp_close)
289 	PHP_FE_END
290 };
291 
292 zend_module_entry php_ftp_module_entry = {
293 	STANDARD_MODULE_HEADER_EX,
294 	NULL,
295 	NULL,
296 	"ftp",
297 	php_ftp_functions,
298 	PHP_MINIT(ftp),
299 	NULL,
300 	NULL,
301 	NULL,
302 	PHP_MINFO(ftp),
303 	PHP_FTP_VERSION,
304 	STANDARD_MODULE_PROPERTIES
305 };
306 
307 #if COMPILE_DL_FTP
308 ZEND_GET_MODULE(php_ftp)
309 #endif
310 
ftp_destructor_ftpbuf(zend_resource *rsrc)311 static void ftp_destructor_ftpbuf(zend_resource *rsrc)
312 {
313 	ftpbuf_t *ftp = (ftpbuf_t *)rsrc->ptr;
314 
315 	ftp_close(ftp);
316 }
317 
PHP_MINIT_FUNCTIONnull318 PHP_MINIT_FUNCTION(ftp)
319 {
320 #ifdef HAVE_FTP_SSL
321 #if OPENSSL_VERSION_NUMBER < 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
322 	SSL_library_init();
323 	OpenSSL_add_all_ciphers();
324 	OpenSSL_add_all_digests();
325 	OpenSSL_add_all_algorithms();
326 
327 	SSL_load_error_strings();
328 #endif
329 #endif
330 
331 	le_ftpbuf = zend_register_list_destructors_ex(ftp_destructor_ftpbuf, NULL, le_ftpbuf_name, module_number);
332 	REGISTER_LONG_CONSTANT("FTP_ASCII",  FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
333 	REGISTER_LONG_CONSTANT("FTP_TEXT",   FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
334 	REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
335 	REGISTER_LONG_CONSTANT("FTP_IMAGE",  FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
336 	REGISTER_LONG_CONSTANT("FTP_AUTORESUME", PHP_FTP_AUTORESUME, CONST_PERSISTENT | CONST_CS);
337 	REGISTER_LONG_CONSTANT("FTP_TIMEOUT_SEC", PHP_FTP_OPT_TIMEOUT_SEC, CONST_PERSISTENT | CONST_CS);
338 	REGISTER_LONG_CONSTANT("FTP_AUTOSEEK", PHP_FTP_OPT_AUTOSEEK, CONST_PERSISTENT | CONST_CS);
339 	REGISTER_LONG_CONSTANT("FTP_USEPASVADDRESS", PHP_FTP_OPT_USEPASVADDRESS, CONST_PERSISTENT | CONST_CS);
340 	REGISTER_LONG_CONSTANT("FTP_FAILED", PHP_FTP_FAILED, CONST_PERSISTENT | CONST_CS);
341 	REGISTER_LONG_CONSTANT("FTP_FINISHED", PHP_FTP_FINISHED, CONST_PERSISTENT | CONST_CS);
342 	REGISTER_LONG_CONSTANT("FTP_MOREDATA", PHP_FTP_MOREDATA, CONST_PERSISTENT | CONST_CS);
343 	return SUCCESS;
344 }
345 
PHP_MINFO_FUNCTIONnull346 PHP_MINFO_FUNCTION(ftp)
347 {
348 	php_info_print_table_start();
349 	php_info_print_table_row(2, "FTP support", "enabled");
350 #ifdef HAVE_FTP_SSL
351 	php_info_print_table_row(2, "FTPS support", "enabled");
352 #else
353 	php_info_print_table_row(2, "FTPS support", "disabled");
354 #endif
355 	php_info_print_table_end();
356 }
357 
358 #define	XTYPE(xtype, mode)	{ \
359 								if (mode != FTPTYPE_ASCII && mode != FTPTYPE_IMAGE) { \
360 									php_error_docref(NULL, E_WARNING, "Mode must be FTP_ASCII or FTP_BINARY"); \
361 									RETURN_FALSE; \
362 								} \
363 								xtype = mode; \
364 							}
365 
366 
367 /* {{{ proto resource ftp_connect(string host [, int port [, int timeout]])
368    Opens a FTP stream */
PHP_FUNCTIONnull369 PHP_FUNCTION(ftp_connect)
370 {
371 	ftpbuf_t	*ftp;
372 	char		*host;
373 	size_t		host_len;
374 	zend_long 		port = 0;
375 	zend_long		timeout_sec = FTP_DEFAULT_TIMEOUT;
376 
377 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
378 		return;
379 	}
380 
381 	if (timeout_sec <= 0) {
382 		php_error_docref(NULL, E_WARNING, "Timeout has to be greater than 0");
383 		RETURN_FALSE;
384 	}
385 
386 	/* connect */
387 	if (!(ftp = ftp_open(host, (short)port, timeout_sec))) {
388 		RETURN_FALSE;
389 	}
390 
391 	/* autoseek for resuming */
392 	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;
393 	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS;
394 #ifdef HAVE_FTP_SSL
395 	/* disable ssl */
396 	ftp->use_ssl = 0;
397 #endif
398 
399 	RETURN_RES(zend_register_resource(ftp, le_ftpbuf));
400 }
401 /* }}} */
402 
403 #ifdef HAVE_FTP_SSL
404 /* {{{ proto resource ftp_ssl_connect(string host [, int port [, int timeout]])
405    Opens a FTP-SSL stream */
PHP_FUNCTIONnull406 PHP_FUNCTION(ftp_ssl_connect)
407 {
408 	ftpbuf_t	*ftp;
409 	char		*host;
410 	size_t		host_len;
411 	zend_long		port = 0;
412 	zend_long		timeout_sec = FTP_DEFAULT_TIMEOUT;
413 
414 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
415 		return;
416 	}
417 
418 	if (timeout_sec <= 0) {
419 		php_error_docref(NULL, E_WARNING, "Timeout has to be greater than 0");
420 		RETURN_FALSE;
421 	}
422 
423 	/* connect */
424 	if (!(ftp = ftp_open(host, (short)port, timeout_sec))) {
425 		RETURN_FALSE;
426 	}
427 
428 	/* autoseek for resuming */
429 	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;
430 	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS;
431 	/* enable ssl */
432 	ftp->use_ssl = 1;
433 
434 	RETURN_RES(zend_register_resource(ftp, le_ftpbuf));
435 }
436 /* }}} */
437 #endif
438 
439 /* {{{ proto bool ftp_login(resource stream, string username, string password)
440    Logs into the FTP server */
PHP_FUNCTIONnull441 PHP_FUNCTION(ftp_login)
442 {
443 	zval 		*z_ftp;
444 	ftpbuf_t	*ftp;
445 	char *user, *pass;
446 	size_t user_len, pass_len;
447 
448 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &z_ftp, &user, &user_len, &pass, &pass_len) == FAILURE) {
449 		return;
450 	}
451 
452 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
453 		RETURN_FALSE;
454 	}
455 
456 	/* log in */
457 	if (!ftp_login(ftp, user, user_len, pass, pass_len)) {
458 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
459 		RETURN_FALSE;
460 	}
461 
462 	RETURN_TRUE;
463 }
464 /* }}} */
465 
466 /* {{{ proto string ftp_pwd(resource stream)
467    Returns the present working directory */
PHP_FUNCTIONnull468 PHP_FUNCTION(ftp_pwd)
469 {
470 	zval 		*z_ftp;
471 	ftpbuf_t	*ftp;
472 	const char	*pwd;
473 
474 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ftp) == FAILURE) {
475 		return;
476 	}
477 
478 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
479 		RETURN_FALSE;
480 	}
481 
482 	if (!(pwd = ftp_pwd(ftp))) {
483 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
484 		RETURN_FALSE;
485 	}
486 
487 	RETURN_STRING((char*) pwd);
488 }
489 /* }}} */
490 
491 /* {{{ proto bool ftp_cdup(resource stream)
492    Changes to the parent directory */
PHP_FUNCTIONnull493 PHP_FUNCTION(ftp_cdup)
494 {
495 	zval 		*z_ftp;
496 	ftpbuf_t	*ftp;
497 
498 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ftp) == FAILURE) {
499 		return;
500 	}
501 
502 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
503 		RETURN_FALSE;
504 	}
505 
506 	if (!ftp_cdup(ftp)) {
507 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
508 		RETURN_FALSE;
509 	}
510 
511 	RETURN_TRUE;
512 }
513 /* }}} */
514 
515 /* {{{ proto bool ftp_chdir(resource stream, string directory)
516    Changes directories */
PHP_FUNCTIONnull517 PHP_FUNCTION(ftp_chdir)
518 {
519 	zval		*z_ftp;
520 	ftpbuf_t	*ftp;
521 	char		*dir;
522 	size_t			dir_len;
523 
524 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &dir, &dir_len) == FAILURE) {
525 		return;
526 	}
527 
528 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
529 		RETURN_FALSE;
530 	}
531 
532 	/* change directories */
533 	if (!ftp_chdir(ftp, dir, dir_len)) {
534 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
535 		RETURN_FALSE;
536 	}
537 
538 	RETURN_TRUE;
539 }
540 /* }}} */
541 
542 /* {{{ proto bool ftp_exec(resource stream, string command)
543    Requests execution of a program on the FTP server */
PHP_FUNCTIONnull544 PHP_FUNCTION(ftp_exec)
545 {
546 	zval		*z_ftp;
547 	ftpbuf_t	*ftp;
548 	char		*cmd;
549 	size_t			cmd_len;
550 
551 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &cmd, &cmd_len) == FAILURE) {
552 		return;
553 	}
554 
555 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
556 		RETURN_FALSE;
557 	}
558 
559 	/* execute serverside command */
560 	if (!ftp_exec(ftp, cmd, cmd_len)) {
561 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
562 		RETURN_FALSE;
563 	}
564 
565 	RETURN_TRUE;
566 }
567 /* }}} */
568 
569 /* {{{ proto array ftp_raw(resource stream, string command)
570    Sends a literal command to the FTP server */
PHP_FUNCTIONnull571 PHP_FUNCTION(ftp_raw)
572 {
573 	zval		*z_ftp;
574 	ftpbuf_t	*ftp;
575 	char		*cmd;
576 	size_t			cmd_len;
577 
578 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &cmd, &cmd_len) == FAILURE) {
579 		return;
580 	}
581 
582 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
583 		RETURN_FALSE;
584 	}
585 
586 	/* execute arbitrary ftp command */
587 	ftp_raw(ftp, cmd, cmd_len, return_value);
588 }
589 /* }}} */
590 
591 /* {{{ proto string ftp_mkdir(resource stream, string directory)
592    Creates a directory and returns the absolute path for the new directory or false on error */
PHP_FUNCTIONnull593 PHP_FUNCTION(ftp_mkdir)
594 {
595 	zval		*z_ftp;
596 	ftpbuf_t	*ftp;
597 	char		*dir;
598 	zend_string *tmp;
599 	size_t		dir_len;
600 
601 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &dir, &dir_len) == FAILURE) {
602 		return;
603 	}
604 
605 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
606 		RETURN_FALSE;
607 	}
608 
609 	/* create directory */
610 	if (NULL == (tmp = ftp_mkdir(ftp, dir, dir_len))) {
611 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
612 		RETURN_FALSE;
613 	}
614 
615 	RETURN_STR(tmp);
616 }
617 /* }}} */
618 
619 /* {{{ proto bool ftp_rmdir(resource stream, string directory)
620    Removes a directory */
PHP_FUNCTIONnull621 PHP_FUNCTION(ftp_rmdir)
622 {
623 	zval		*z_ftp;
624 	ftpbuf_t	*ftp;
625 	char		*dir;
626 	size_t		dir_len;
627 
628 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &dir, &dir_len) == FAILURE) {
629 		return;
630 	}
631 
632 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
633 		RETURN_FALSE;
634 	}
635 
636 	/* remove directorie */
637 	if (!ftp_rmdir(ftp, dir, dir_len)) {
638 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
639 		RETURN_FALSE;
640 	}
641 
642 	RETURN_TRUE;
643 }
644 /* }}} */
645 
646 /* {{{ proto int ftp_chmod(resource stream, int mode, string filename)
647    Sets permissions on a file */
PHP_FUNCTIONnull648 PHP_FUNCTION(ftp_chmod)
649 {
650 	zval		*z_ftp;
651 	ftpbuf_t	*ftp;
652 	char		*filename;
653 	size_t		filename_len;
654 	zend_long		mode;
655 
656 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlp", &z_ftp, &mode, &filename, &filename_len) == FAILURE) {
657 		RETURN_FALSE;
658 	}
659 
660 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
661 		RETURN_FALSE;
662 	}
663 
664 	if (!ftp_chmod(ftp, mode, filename, filename_len)) {
665 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
666 		RETURN_FALSE;
667 	}
668 
669 	RETURN_LONG(mode);
670 }
671 /* }}} */
672 
673 /* {{{ proto bool ftp_alloc(resource stream, int size[, &response])
674    Attempt to allocate space on the remote FTP server */
PHP_FUNCTIONnull675 PHP_FUNCTION(ftp_alloc)
676 {
677 	zval		*z_ftp, *zresponse = NULL;
678 	ftpbuf_t	*ftp;
679 	zend_long		size, ret;
680 	zend_string	*response = NULL;
681 
682 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|z", &z_ftp, &size, &zresponse) == FAILURE) {
683 		RETURN_FALSE;
684 	}
685 
686 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
687 		RETURN_FALSE;
688 	}
689 
690 	ret = ftp_alloc(ftp, size, zresponse ? &response : NULL);
691 
692 	if (response) {
693 		ZEND_TRY_ASSIGN_REF_STR(zresponse, response);
694 	}
695 
696 	if (!ret) {
697 		RETURN_FALSE;
698 	}
699 
700 	RETURN_TRUE;
701 }
702 /* }}} */
703 
704 /* {{{ proto array ftp_nlist(resource stream, string directory)
705    Returns an array of filenames in the given directory */
PHP_FUNCTIONnull706 PHP_FUNCTION(ftp_nlist)
707 {
708 	zval		*z_ftp;
709 	ftpbuf_t	*ftp;
710 	char		**nlist, **ptr, *dir;
711 	size_t		dir_len;
712 
713 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp", &z_ftp, &dir, &dir_len) == FAILURE) {
714 		return;
715 	}
716 
717 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
718 		RETURN_FALSE;
719 	}
720 
721 	/* get list of files */
722 	if (NULL == (nlist = ftp_nlist(ftp, dir, dir_len))) {
723 		RETURN_FALSE;
724 	}
725 
726 	array_init(return_value);
727 	for (ptr = nlist; *ptr; ptr++) {
728 		add_next_index_string(return_value, *ptr);
729 	}
730 	efree(nlist);
731 }
732 /* }}} */
733 
734 /* {{{ proto array ftp_rawlist(resource stream, string directory [, bool recursive])
735    Returns a detailed listing of a directory as an array of output lines */
PHP_FUNCTIONnull736 PHP_FUNCTION(ftp_rawlist)
737 {
738 	zval		*z_ftp;
739 	ftpbuf_t	*ftp;
740 	char		**llist, **ptr, *dir;
741 	size_t		dir_len;
742 	zend_bool	recursive = 0;
743 
744 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|b", &z_ftp, &dir, &dir_len, &recursive) == FAILURE) {
745 		return;
746 	}
747 
748 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
749 		RETURN_FALSE;
750 	}
751 
752 	/* get raw directory listing */
753 	if (NULL == (llist = ftp_list(ftp, dir, dir_len, recursive))) {
754 		RETURN_FALSE;
755 	}
756 
757 	array_init(return_value);
758 	for (ptr = llist; *ptr; ptr++) {
759 		add_next_index_string(return_value, *ptr);
760 	}
761 	efree(llist);
762 }
763 /* }}} */
764 
765 /* {{{ proto array ftp_mlsd(resource stream, string directory)
766    Returns a detailed listing of a directory as an array of parsed output lines */
PHP_FUNCTIONnull767 PHP_FUNCTION(ftp_mlsd)
768 {
769 	zval		*z_ftp;
770 	ftpbuf_t	*ftp;
771 	char		**llist, **ptr, *dir;
772 	size_t		dir_len;
773 	zval		entry;
774 
775 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &dir, &dir_len) == FAILURE) {
776 		return;
777 	}
778 
779 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
780 		RETURN_FALSE;
781 	}
782 
783 	/* get raw directory listing */
784 	if (NULL == (llist = ftp_mlsd(ftp, dir, dir_len))) {
785 		RETURN_FALSE;
786 	}
787 
788 	array_init(return_value);
789 	for (ptr = llist; *ptr; ptr++) {
790 		array_init(&entry);
791 		if (ftp_mlsd_parse_line(Z_ARRVAL_P(&entry), *ptr) == SUCCESS) {
792 			zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &entry);
793 		} else {
794 			zval_ptr_dtor(&entry);
795 		}
796 	}
797 
798 	efree(llist);
799 }
800 /* }}} */
801 
802 /* {{{ proto string ftp_systype(resource stream)
803    Returns the system type identifier */
PHP_FUNCTIONnull804 PHP_FUNCTION(ftp_systype)
805 {
806 	zval		*z_ftp;
807 	ftpbuf_t	*ftp;
808 	const char	*syst;
809 
810 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ftp) == FAILURE) {
811 		return;
812 	}
813 
814 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
815 		RETURN_FALSE;
816 	}
817 
818 	if (NULL == (syst = ftp_syst(ftp))) {
819 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
820 		RETURN_FALSE;
821 	}
822 
823 	RETURN_STRING((char*) syst);
824 }
825 /* }}} */
826 
827 /* {{{ proto bool ftp_fget(resource stream, resource fp, string remote_file, [, int mode [, int resumepos]])
828    Retrieves a file from the FTP server and writes it to an open file */
PHP_FUNCTIONnull829 PHP_FUNCTION(ftp_fget)
830 {
831 	zval		*z_ftp, *z_file;
832 	ftpbuf_t	*ftp;
833 	ftptype_t	xtype;
834 	php_stream	*stream;
835 	char		*file;
836 	size_t		file_len;
837 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
838 
839 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs|ll", &z_ftp, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
840 		return;
841 	}
842 
843 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
844 		RETURN_FALSE;
845 	}
846 	php_stream_from_res(stream, Z_RES_P(z_file));
847 	XTYPE(xtype, mode);
848 
849 	/* ignore autoresume if autoseek is switched off */
850 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
851 		resumepos = 0;
852 	}
853 
854 	if (ftp->autoseek && resumepos) {
855 		/* if autoresume is wanted seek to end */
856 		if (resumepos == PHP_FTP_AUTORESUME) {
857 			php_stream_seek(stream, 0, SEEK_END);
858 			resumepos = php_stream_tell(stream);
859 		} else {
860 			php_stream_seek(stream, resumepos, SEEK_SET);
861 		}
862 	}
863 
864 	if (!ftp_get(ftp, stream, file, file_len, xtype, resumepos)) {
865 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
866 		RETURN_FALSE;
867 	}
868 
869 	RETURN_TRUE;
870 }
871 /* }}} */
872 
873 /* {{{ proto int ftp_nb_fget(resource stream, resource fp, string remote_file [, int mode [, int resumepos]])
874    Retrieves a file from the FTP server asynchronly and writes it to an open file */
PHP_FUNCTIONnull875 PHP_FUNCTION(ftp_nb_fget)
876 {
877 	zval		*z_ftp, *z_file;
878 	ftpbuf_t	*ftp;
879 	ftptype_t	xtype;
880 	php_stream	*stream;
881 	char		*file;
882 	size_t		file_len;
883 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0, ret;
884 
885 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs|ll", &z_ftp, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
886 		return;
887 	}
888 
889 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
890 		RETURN_FALSE;
891 	}
892 	php_stream_from_res(stream, Z_RES_P(z_file));
893 	XTYPE(xtype, mode);
894 
895 	/* ignore autoresume if autoseek is switched off */
896 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
897 		resumepos = 0;
898 	}
899 
900 	if (ftp->autoseek && resumepos) {
901 		/* if autoresume is wanted seek to end */
902 		if (resumepos == PHP_FTP_AUTORESUME) {
903 			php_stream_seek(stream, 0, SEEK_END);
904 			resumepos = php_stream_tell(stream);
905 		} else {
906 			php_stream_seek(stream, resumepos, SEEK_SET);
907 		}
908 	}
909 
910 	/* configuration */
911 	ftp->direction = 0;   /* recv */
912 	ftp->closestream = 0; /* do not close */
913 
914 	if ((ret = ftp_nb_get(ftp, stream, file, file_len, xtype, resumepos)) == PHP_FTP_FAILED) {
915 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
916 		RETURN_LONG(ret);
917 	}
918 
919 	RETURN_LONG(ret);
920 }
921 /* }}} */
922 
923 /* {{{ proto bool ftp_pasv(resource stream, bool pasv)
924    Turns passive mode on or off */
PHP_FUNCTIONnull925 PHP_FUNCTION(ftp_pasv)
926 {
927 	zval		*z_ftp;
928 	ftpbuf_t	*ftp;
929 	zend_bool	pasv;
930 
931 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rb", &z_ftp, &pasv) == FAILURE) {
932 		return;
933 	}
934 
935 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
936 		RETURN_FALSE;
937 	}
938 
939 	if (!ftp_pasv(ftp, pasv ? 1 : 0)) {
940 		RETURN_FALSE;
941 	}
942 
943 	RETURN_TRUE;
944 }
945 /* }}} */
946 
947 /* {{{ proto bool ftp_get(resource stream, string local_file, string remote_file [, int mode [, int resume_pos]])
948    Retrieves a file from the FTP server and writes it to a local file */
PHP_FUNCTIONnull949 PHP_FUNCTION(ftp_get)
950 {
951 	zval		*z_ftp;
952 	ftpbuf_t	*ftp;
953 	ftptype_t	xtype;
954 	php_stream	*outstream;
955 	char		*local, *remote;
956 	size_t		local_len, remote_len;
957 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
958 
959 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rpp|ll", &z_ftp, &local, &local_len, &remote, &remote_len, &mode, &resumepos) == FAILURE) {
960 		return;
961 	}
962 
963 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
964 		RETURN_FALSE;
965 	}
966 	XTYPE(xtype, mode);
967 
968 	/* ignore autoresume if autoseek is switched off */
969 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
970 		resumepos = 0;
971 	}
972 
973 #ifdef PHP_WIN32
974 	mode = FTPTYPE_IMAGE;
975 #endif
976 
977 	if (ftp->autoseek && resumepos) {
978 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt+" : "rb+", REPORT_ERRORS, NULL);
979 		if (outstream == NULL) {
980 			outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
981 		}
982 		if (outstream != NULL) {
983 			/* if autoresume is wanted seek to end */
984 			if (resumepos == PHP_FTP_AUTORESUME) {
985 				php_stream_seek(outstream, 0, SEEK_END);
986 				resumepos = php_stream_tell(outstream);
987 			} else {
988 				php_stream_seek(outstream, resumepos, SEEK_SET);
989 			}
990 		}
991 	} else {
992 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
993 	}
994 
995 	if (outstream == NULL)	{
996 		php_error_docref(NULL, E_WARNING, "Error opening %s", local);
997 		RETURN_FALSE;
998 	}
999 
1000 	if (!ftp_get(ftp, outstream, remote, remote_len, xtype, resumepos)) {
1001 		php_stream_close(outstream);
1002 		VCWD_UNLINK(local);
1003 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1004 		RETURN_FALSE;
1005 	}
1006 
1007 	php_stream_close(outstream);
1008 	RETURN_TRUE;
1009 }
1010 /* }}} */
1011 
1012 /* {{{ proto int ftp_nb_get(resource stream, string local_file, string remote_file, [, int mode [, int resume_pos]])
1013    Retrieves a file from the FTP server nbhronly and writes it to a local file */
PHP_FUNCTIONnull1014 PHP_FUNCTION(ftp_nb_get)
1015 {
1016 	zval		*z_ftp;
1017 	ftpbuf_t	*ftp;
1018 	ftptype_t	xtype;
1019 	php_stream	*outstream;
1020 	char		*local, *remote;
1021 	size_t		local_len, remote_len;
1022 	int ret;
1023 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
1024 
1025 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss|ll", &z_ftp, &local, &local_len, &remote, &remote_len, &mode, &resumepos) == FAILURE) {
1026 		return;
1027 	}
1028 
1029 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1030 		RETURN_FALSE;
1031 	}
1032 	XTYPE(xtype, mode);
1033 
1034 	/* ignore autoresume if autoseek is switched off */
1035 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
1036 		resumepos = 0;
1037 	}
1038 #ifdef PHP_WIN32
1039 	mode = FTPTYPE_IMAGE;
1040 #endif
1041 	if (ftp->autoseek && resumepos) {
1042 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt+" : "rb+", REPORT_ERRORS, NULL);
1043 		if (outstream == NULL) {
1044 			outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
1045 		}
1046 		if (outstream != NULL) {
1047 			/* if autoresume is wanted seek to end */
1048 			if (resumepos == PHP_FTP_AUTORESUME) {
1049 				php_stream_seek(outstream, 0, SEEK_END);
1050 				resumepos = php_stream_tell(outstream);
1051 			} else {
1052 				php_stream_seek(outstream, resumepos, SEEK_SET);
1053 			}
1054 		}
1055 	} else {
1056 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
1057 	}
1058 
1059 	if (outstream == NULL)	{
1060 		php_error_docref(NULL, E_WARNING, "Error opening %s", local);
1061 		RETURN_FALSE;
1062 	}
1063 
1064 	/* configuration */
1065 	ftp->direction = 0;   /* recv */
1066 	ftp->closestream = 1; /* do close */
1067 
1068 	if ((ret = ftp_nb_get(ftp, outstream, remote, remote_len, xtype, resumepos)) == PHP_FTP_FAILED) {
1069 		php_stream_close(outstream);
1070 		ftp->stream = NULL;
1071 		VCWD_UNLINK(local);
1072 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1073 		RETURN_LONG(PHP_FTP_FAILED);
1074 	}
1075 
1076 	if (ret == PHP_FTP_FINISHED){
1077 		php_stream_close(outstream);
1078 		ftp->stream = NULL;
1079 	}
1080 
1081 	RETURN_LONG(ret);
1082 }
1083 /* }}} */
1084 
1085 /* {{{ proto int ftp_nb_continue(resource stream)
1086    Continues retrieving/sending a file nbronously */
PHP_FUNCTIONnull1087 PHP_FUNCTION(ftp_nb_continue)
1088 {
1089 	zval		*z_ftp;
1090 	ftpbuf_t	*ftp;
1091 	zend_long		ret;
1092 
1093 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ftp) == FAILURE) {
1094 		return;
1095 	}
1096 
1097 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1098 		RETURN_FALSE;
1099 	}
1100 
1101 	if (!ftp->nb) {
1102 		php_error_docref(NULL, E_WARNING, "no nbronous transfer to continue.");
1103 		RETURN_LONG(PHP_FTP_FAILED);
1104 	}
1105 
1106 	if (ftp->direction) {
1107 		ret=ftp_nb_continue_write(ftp);
1108 	} else {
1109 		ret=ftp_nb_continue_read(ftp);
1110 	}
1111 
1112 	if (ret != PHP_FTP_MOREDATA && ftp->closestream) {
1113 		php_stream_close(ftp->stream);
1114 		ftp->stream = NULL;
1115 	}
1116 
1117 	if (ret == PHP_FTP_FAILED) {
1118 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1119 	}
1120 
1121 	RETURN_LONG(ret);
1122 }
1123 /* }}} */
1124 
1125 /* {{{ proto bool ftp_fput(resource stream, string remote_file, resource fp [, int mode [, int startpos]])
1126    Stores a file from an open file to the FTP server */
PHP_FUNCTIONnull1127 PHP_FUNCTION(ftp_fput)
1128 {
1129 	zval		*z_ftp, *z_file;
1130 	ftpbuf_t	*ftp;
1131 	ftptype_t	xtype;
1132 	size_t		remote_len;
1133 	zend_long		mode=FTPTYPE_IMAGE, startpos=0;
1134 	php_stream	*stream;
1135 	char		*remote;
1136 
1137 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsr|ll", &z_ftp, &remote, &remote_len, &z_file, &mode, &startpos) == FAILURE) {
1138 		return;
1139 	}
1140 
1141 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1142 		RETURN_FALSE;
1143 	}
1144 	php_stream_from_zval(stream, z_file);
1145 	XTYPE(xtype, mode);
1146 
1147 	/* ignore autoresume if autoseek is switched off */
1148 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
1149 		startpos = 0;
1150 	}
1151 
1152 	if (ftp->autoseek && startpos) {
1153 		/* if autoresume is wanted ask for remote size */
1154 		if (startpos == PHP_FTP_AUTORESUME) {
1155 			startpos = ftp_size(ftp, remote, remote_len);
1156 			if (startpos < 0) {
1157 				startpos = 0;
1158 			}
1159 		}
1160 		if (startpos) {
1161 			php_stream_seek(stream, startpos, SEEK_SET);
1162 		}
1163 	}
1164 
1165 	if (!ftp_put(ftp, remote, remote_len, stream, xtype, startpos)) {
1166 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1167 		RETURN_FALSE;
1168 	}
1169 
1170 	RETURN_TRUE;
1171 }
1172 /* }}} */
1173 
1174 /* {{{ proto int ftp_nb_fput(resource stream, string remote_file, resource fp [, int mode [, int startpos]])
1175    Stores a file from an open file to the FTP server nbronly */
PHP_FUNCTIONnull1176 PHP_FUNCTION(ftp_nb_fput)
1177 {
1178 	zval		*z_ftp, *z_file;
1179 	ftpbuf_t	*ftp;
1180 	ftptype_t	xtype;
1181 	size_t		remote_len;
1182 	int             ret;
1183 	zend_long	mode=FTPTYPE_IMAGE, startpos=0;
1184 	php_stream	*stream;
1185 	char		*remote;
1186 
1187 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsr|ll", &z_ftp, &remote, &remote_len, &z_file, &mode, &startpos) == FAILURE) {
1188 		return;
1189 	}
1190 
1191 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1192 		RETURN_FALSE;
1193 	}
1194 	php_stream_from_res(stream, Z_RES_P(z_file));
1195 	XTYPE(xtype, mode);
1196 
1197 	/* ignore autoresume if autoseek is switched off */
1198 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
1199 		startpos = 0;
1200 	}
1201 
1202 	if (ftp->autoseek && startpos) {
1203 		/* if autoresume is wanted ask for remote size */
1204 		if (startpos == PHP_FTP_AUTORESUME) {
1205 			startpos = ftp_size(ftp, remote, remote_len);
1206 			if (startpos < 0) {
1207 				startpos = 0;
1208 			}
1209 		}
1210 		if (startpos) {
1211 			php_stream_seek(stream, startpos, SEEK_SET);
1212 		}
1213 	}
1214 
1215 	/* configuration */
1216 	ftp->direction = 1;   /* send */
1217 	ftp->closestream = 0; /* do not close */
1218 
1219 	if (((ret = ftp_nb_put(ftp, remote, remote_len, stream, xtype, startpos)) == PHP_FTP_FAILED)) {
1220 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1221 		RETURN_LONG(ret);
1222 	}
1223 
1224 	RETURN_LONG(ret);
1225 }
1226 /* }}} */
1227 
1228 
1229 /* {{{ proto bool ftp_put(resource stream, string remote_file, string local_file [, int mode [, int startpos]])
1230    Stores a file on the FTP server */
PHP_FUNCTIONnull1231 PHP_FUNCTION(ftp_put)
1232 {
1233 	zval		*z_ftp;
1234 	ftpbuf_t	*ftp;
1235 	ftptype_t	xtype;
1236 	char		*remote, *local;
1237 	size_t		remote_len, local_len;
1238 	zend_long		mode=FTPTYPE_IMAGE, startpos=0;
1239 	php_stream 	*instream;
1240 
1241 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rpp|ll", &z_ftp, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
1242 		return;
1243 	}
1244 
1245 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1246 		RETURN_FALSE;
1247 	}
1248 	XTYPE(xtype, mode);
1249 
1250 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
1251 		RETURN_FALSE;
1252 	}
1253 
1254 	/* ignore autoresume if autoseek is switched off */
1255 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
1256 		startpos = 0;
1257 	}
1258 
1259 	if (ftp->autoseek && startpos) {
1260 		/* if autoresume is wanted ask for remote size */
1261 		if (startpos == PHP_FTP_AUTORESUME) {
1262 			startpos = ftp_size(ftp, remote, remote_len);
1263 			if (startpos < 0) {
1264 				startpos = 0;
1265 			}
1266 		}
1267 		if (startpos) {
1268 			php_stream_seek(instream, startpos, SEEK_SET);
1269 		}
1270 	}
1271 
1272 	if (!ftp_put(ftp, remote, remote_len, instream, xtype, startpos)) {
1273 		php_stream_close(instream);
1274 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1275 		RETURN_FALSE;
1276 	}
1277 	php_stream_close(instream);
1278 
1279 	RETURN_TRUE;
1280 }
1281 /* }}} */
1282 
1283 /* {{{ proto bool ftp_append(resource stream, string remote_file, string local_file [, int mode])
1284    Append content of a file a another file on the FTP server */
PHP_FUNCTIONnull1285 PHP_FUNCTION(ftp_append)
1286 {
1287 	zval		*z_ftp;
1288 	ftpbuf_t	*ftp;
1289 	ftptype_t	xtype;
1290 	char		*remote, *local;
1291 	size_t		remote_len, local_len;
1292 	zend_long		mode=FTPTYPE_IMAGE;
1293 	php_stream 	*instream;
1294 
1295 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rpp|l", &z_ftp, &remote, &remote_len, &local, &local_len, &mode) == FAILURE) {
1296 		return;
1297 	}
1298 
1299 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1300 		RETURN_FALSE;
1301 	}
1302 	XTYPE(xtype, mode);
1303 
1304 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
1305 		RETURN_FALSE;
1306 	}
1307 
1308 	if (!ftp_append(ftp, remote, remote_len, instream, xtype)) {
1309 		php_stream_close(instream);
1310 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1311 		RETURN_FALSE;
1312 	}
1313 	php_stream_close(instream);
1314 
1315 	RETURN_TRUE;
1316 }
1317 /* }}} */
1318 
1319 /* {{{ proto int ftp_nb_put(resource stream, string remote_file, string local_file [, int mode [, int startpos]])
1320    Stores a file on the FTP server */
PHP_FUNCTIONnull1321 PHP_FUNCTION(ftp_nb_put)
1322 {
1323 	zval		*z_ftp;
1324 	ftpbuf_t	*ftp;
1325 	ftptype_t	xtype;
1326 	char		*remote, *local;
1327 	size_t		remote_len, local_len;
1328 	zend_long		mode=FTPTYPE_IMAGE, startpos=0, ret;
1329 	php_stream 	*instream;
1330 
1331 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rpp|ll", &z_ftp, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
1332 		return;
1333 	}
1334 
1335 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1336 		RETURN_FALSE;
1337 	}
1338 	XTYPE(xtype, mode);
1339 
1340 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
1341 		RETURN_FALSE;
1342 	}
1343 
1344 	/* ignore autoresume if autoseek is switched off */
1345 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
1346 		startpos = 0;
1347 	}
1348 
1349 	if (ftp->autoseek && startpos) {
1350 		/* if autoresume is wanted ask for remote size */
1351 		if (startpos == PHP_FTP_AUTORESUME) {
1352 			startpos = ftp_size(ftp, remote, remote_len);
1353 			if (startpos < 0) {
1354 				startpos = 0;
1355 			}
1356 		}
1357 		if (startpos) {
1358 			php_stream_seek(instream, startpos, SEEK_SET);
1359 		}
1360 	}
1361 
1362 	/* configuration */
1363 	ftp->direction = 1;   /* send */
1364 	ftp->closestream = 1; /* do close */
1365 
1366 	ret = ftp_nb_put(ftp, remote, remote_len, instream, xtype, startpos);
1367 
1368 	if (ret != PHP_FTP_MOREDATA) {
1369 		php_stream_close(instream);
1370 		ftp->stream = NULL;
1371 	}
1372 
1373 	if (ret == PHP_FTP_FAILED) {
1374 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1375 	}
1376 
1377 	RETURN_LONG(ret);
1378 }
1379 /* }}} */
1380 
1381 /* {{{ proto int ftp_size(resource stream, string filename)
1382    Returns the size of the file, or -1 on error */
PHP_FUNCTIONnull1383 PHP_FUNCTION(ftp_size)
1384 {
1385 	zval		*z_ftp;
1386 	ftpbuf_t	*ftp;
1387 	char		*file;
1388 	size_t		file_len;
1389 
1390 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp", &z_ftp, &file, &file_len) == FAILURE) {
1391 		return;
1392 	}
1393 
1394 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1395 		RETURN_FALSE;
1396 	}
1397 
1398 	/* get file size */
1399 	RETURN_LONG(ftp_size(ftp, file, file_len));
1400 }
1401 /* }}} */
1402 
1403 /* {{{ proto int ftp_mdtm(resource stream, string filename)
1404    Returns the last modification time of the file, or -1 on error */
PHP_FUNCTIONnull1405 PHP_FUNCTION(ftp_mdtm)
1406 {
1407 	zval		*z_ftp;
1408 	ftpbuf_t	*ftp;
1409 	char		*file;
1410 	size_t		file_len;
1411 
1412 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp", &z_ftp, &file, &file_len) == FAILURE) {
1413 		return;
1414 	}
1415 
1416 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1417 		RETURN_FALSE;
1418 	}
1419 
1420 	/* get file mod time */
1421 	RETURN_LONG(ftp_mdtm(ftp, file, file_len));
1422 }
1423 /* }}} */
1424 
1425 /* {{{ proto bool ftp_rename(resource stream, string src, string dest)
1426    Renames the given file to a new path */
PHP_FUNCTIONnull1427 PHP_FUNCTION(ftp_rename)
1428 {
1429 	zval		*z_ftp;
1430 	ftpbuf_t	*ftp;
1431 	char		*src, *dest;
1432 	size_t		src_len, dest_len;
1433 
1434 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &z_ftp, &src, &src_len, &dest, &dest_len) == FAILURE) {
1435 		return;
1436 	}
1437 
1438 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1439 		RETURN_FALSE;
1440 	}
1441 
1442 	/* rename the file */
1443 	if (!ftp_rename(ftp, src, src_len, dest, dest_len)) {
1444 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1445 		RETURN_FALSE;
1446 	}
1447 
1448 	RETURN_TRUE;
1449 }
1450 /* }}} */
1451 
1452 /* {{{ proto bool ftp_delete(resource stream, string file)
1453    Deletes a file */
PHP_FUNCTIONnull1454 PHP_FUNCTION(ftp_delete)
1455 {
1456 	zval		*z_ftp;
1457 	ftpbuf_t	*ftp;
1458 	char		*file;
1459 	size_t		file_len;
1460 
1461 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &file, &file_len) == FAILURE) {
1462 		return;
1463 	}
1464 
1465 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1466 		RETURN_FALSE;
1467 	}
1468 
1469 	/* delete the file */
1470 	if (!ftp_delete(ftp, file, file_len)) {
1471 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1472 		RETURN_FALSE;
1473 	}
1474 
1475 	RETURN_TRUE;
1476 }
1477 /* }}} */
1478 
1479 /* {{{ proto bool ftp_site(resource stream, string cmd)
1480    Sends a SITE command to the server */
PHP_FUNCTIONnull1481 PHP_FUNCTION(ftp_site)
1482 {
1483 	zval		*z_ftp;
1484 	ftpbuf_t	*ftp;
1485 	char		*cmd;
1486 	size_t		cmd_len;
1487 
1488 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &z_ftp, &cmd, &cmd_len) == FAILURE) {
1489 		return;
1490 	}
1491 
1492 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1493 		RETURN_FALSE;
1494 	}
1495 
1496 	/* send the site command */
1497 	if (!ftp_site(ftp, cmd, cmd_len)) {
1498 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1499 		RETURN_FALSE;
1500 	}
1501 
1502 	RETURN_TRUE;
1503 }
1504 /* }}} */
1505 
1506 /* {{{ proto bool ftp_close(resource stream)
1507    Closes the FTP stream */
PHP_FUNCTIONnull1508 PHP_FUNCTION(ftp_close)
1509 {
1510 	zval		*z_ftp;
1511 	ftpbuf_t	*ftp;
1512 
1513 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ftp) == FAILURE) {
1514 		return;
1515 	}
1516 
1517 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1518 		RETURN_FALSE;
1519 	}
1520 
1521 	ftp_quit(ftp);
1522 
1523 	RETURN_BOOL(zend_list_close(Z_RES_P(z_ftp)) == SUCCESS);
1524 }
1525 /* }}} */
1526 
1527 /* {{{ proto bool ftp_set_option(resource stream, int option, mixed value)
1528    Sets an FTP option */
PHP_FUNCTIONnull1529 PHP_FUNCTION(ftp_set_option)
1530 {
1531 	zval		*z_ftp, *z_value;
1532 	zend_long		option;
1533 	ftpbuf_t	*ftp;
1534 
1535 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &z_ftp, &option, &z_value) == FAILURE) {
1536 		return;
1537 	}
1538 
1539 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1540 		RETURN_FALSE;
1541 	}
1542 
1543 	switch (option) {
1544 		case PHP_FTP_OPT_TIMEOUT_SEC:
1545 			if (Z_TYPE_P(z_value) != IS_LONG) {
1546 				php_error_docref(NULL, E_WARNING, "Option TIMEOUT_SEC expects value of type int, %s given",
1547 					zend_zval_type_name(z_value));
1548 				RETURN_FALSE;
1549 			}
1550 			if (Z_LVAL_P(z_value) <= 0) {
1551 				php_error_docref(NULL, E_WARNING, "Timeout has to be greater than 0");
1552 				RETURN_FALSE;
1553 			}
1554 			ftp->timeout_sec = Z_LVAL_P(z_value);
1555 			RETURN_TRUE;
1556 			break;
1557 		case PHP_FTP_OPT_AUTOSEEK:
1558 			if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) {
1559 				php_error_docref(NULL, E_WARNING, "Option AUTOSEEK expects value of type bool, %s given",
1560 					zend_zval_type_name(z_value));
1561 				RETURN_FALSE;
1562 			}
1563 			ftp->autoseek = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0;
1564 			RETURN_TRUE;
1565 			break;
1566 		case PHP_FTP_OPT_USEPASVADDRESS:
1567 			if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) {
1568 				php_error_docref(NULL, E_WARNING, "Option USEPASVADDRESS expects value of type bool, %s given",
1569 					zend_zval_type_name(z_value));
1570 				RETURN_FALSE;
1571 			}
1572 			ftp->usepasvaddress = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0;
1573 			RETURN_TRUE;
1574 			break;
1575 		default:
1576 			php_error_docref(NULL, E_WARNING, "Unknown option '" ZEND_LONG_FMT "'", option);
1577 			RETURN_FALSE;
1578 			break;
1579 	}
1580 }
1581 /* }}} */
1582 
1583 /* {{{ proto mixed ftp_get_option(resource stream, int option)
1584    Gets an FTP option */
PHP_FUNCTIONnull1585 PHP_FUNCTION(ftp_get_option)
1586 {
1587 	zval		*z_ftp;
1588 	zend_long		option;
1589 	ftpbuf_t	*ftp;
1590 
1591 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &z_ftp, &option) == FAILURE) {
1592 		return;
1593 	}
1594 
1595 	if ((ftp = (ftpbuf_t *)zend_fetch_resource(Z_RES_P(z_ftp), le_ftpbuf_name, le_ftpbuf)) == NULL) {
1596 		RETURN_FALSE;
1597 	}
1598 
1599 	switch (option) {
1600 		case PHP_FTP_OPT_TIMEOUT_SEC:
1601 			RETURN_LONG(ftp->timeout_sec);
1602 			break;
1603 		case PHP_FTP_OPT_AUTOSEEK:
1604 			RETURN_BOOL(ftp->autoseek);
1605 			break;
1606 		case PHP_FTP_OPT_USEPASVADDRESS:
1607 			RETURN_BOOL(ftp->usepasvaddress);
1608 			break;
1609 		default:
1610 			php_error_docref(NULL, E_WARNING, "Unknown option '" ZEND_LONG_FMT "'", option);
1611 			RETURN_FALSE;
1612 			break;
1613 	}
1614 }
1615 /* }}} */
1616 
1617 #endif /* HAVE_FTP */
1618