xref: /PHP-8.1/ext/ftp/php_ftp.c (revision abc6fe8f)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Andrew Skalski <askalski@chek.com>                          |
14    |          Stefan Esser <sesser@php.net> (resume functions)            |
15    +----------------------------------------------------------------------+
16  */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include "php.h"
23 
24 #ifdef HAVE_FTP_SSL
25 # include <openssl/ssl.h>
26 #endif
27 
28 #ifdef HAVE_FTP
29 
30 #include "ext/standard/info.h"
31 #include "ext/standard/file.h"
32 #include "Zend/zend_exceptions.h"
33 
34 #include "php_ftp.h"
35 #include "ftp.h"
36 #include "ftp_arginfo.h"
37 
38 static zend_class_entry *php_ftp_ce = NULL;
39 static zend_object_handlers ftp_object_handlers;
40 
41 zend_module_entry php_ftp_module_entry = {
42 	STANDARD_MODULE_HEADER_EX,
43 	NULL,
44 	NULL,
45 	"ftp",
46 	ext_functions,
47 	PHP_MINIT(ftp),
48 	NULL,
49 	NULL,
50 	NULL,
51 	PHP_MINFO(ftp),
52 	PHP_FTP_VERSION,
53 	STANDARD_MODULE_PROPERTIES
54 };
55 
56 #ifdef COMPILE_DL_FTP
57 ZEND_GET_MODULE(php_ftp)
58 #endif
59 
60 typedef struct _php_ftp_object {
61 	ftpbuf_t *ftp;
62 	zend_object std;
63 } php_ftp_object;
64 
ftp_object_to_zend_object(php_ftp_object * obj)65 static inline zend_object *ftp_object_to_zend_object(php_ftp_object *obj) {
66 	return ((zend_object*)(obj + 1)) - 1;
67 }
68 
ftp_object_from_zend_object(zend_object * zobj)69 static inline php_ftp_object *ftp_object_from_zend_object(zend_object *zobj) {
70 	return ((php_ftp_object*)(zobj + 1)) - 1;
71 }
72 
ftp_object_create(zend_class_entry * ce)73 static zend_object* ftp_object_create(zend_class_entry* ce) {
74 	php_ftp_object *obj = zend_object_alloc(sizeof(php_ftp_object), ce);
75 	zend_object *zobj = ftp_object_to_zend_object(obj);
76 	obj->ftp = NULL;
77 	zend_object_std_init(zobj, ce);
78 	object_properties_init(zobj, ce);
79 	zobj->handlers = &ftp_object_handlers;
80 
81 	return zobj;
82 }
83 
ftp_object_get_constructor(zend_object * zobj)84 static zend_function *ftp_object_get_constructor(zend_object *zobj) {
85 	zend_throw_error(NULL, "Cannot directly construct FTP\\Connection, use ftp_connect() or ftp_ssl_connect() instead");
86 	return NULL;
87 }
88 
ftp_object_destroy(zend_object * zobj)89 static void ftp_object_destroy(zend_object *zobj) {
90 	php_ftp_object *obj = ftp_object_from_zend_object(zobj);
91 
92 	if (obj->ftp) {
93 		ftp_close(obj->ftp);
94 	}
95 
96 	zend_object_std_dtor(zobj);
97 }
98 
PHP_MINIT_FUNCTION(ftp)99 PHP_MINIT_FUNCTION(ftp)
100 {
101 #ifdef HAVE_FTP_SSL
102 #if OPENSSL_VERSION_NUMBER < 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
103 	SSL_library_init();
104 	OpenSSL_add_all_ciphers();
105 	OpenSSL_add_all_digests();
106 	OpenSSL_add_all_algorithms();
107 
108 	SSL_load_error_strings();
109 #endif
110 #endif
111 
112 	php_ftp_ce = register_class_FTP_Connection();
113 	php_ftp_ce->create_object = ftp_object_create;
114 
115 	memcpy(&ftp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
116 	ftp_object_handlers.offset = XtOffsetOf(php_ftp_object, std);
117 	ftp_object_handlers.get_constructor = ftp_object_get_constructor;
118 	ftp_object_handlers.free_obj = ftp_object_destroy;
119 	ftp_object_handlers.clone_obj = NULL;
120 
121 	REGISTER_LONG_CONSTANT("FTP_ASCII",  FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
122 	REGISTER_LONG_CONSTANT("FTP_TEXT",   FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
123 	REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
124 	REGISTER_LONG_CONSTANT("FTP_IMAGE",  FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
125 	REGISTER_LONG_CONSTANT("FTP_AUTORESUME", PHP_FTP_AUTORESUME, CONST_PERSISTENT | CONST_CS);
126 	REGISTER_LONG_CONSTANT("FTP_TIMEOUT_SEC", PHP_FTP_OPT_TIMEOUT_SEC, CONST_PERSISTENT | CONST_CS);
127 	REGISTER_LONG_CONSTANT("FTP_AUTOSEEK", PHP_FTP_OPT_AUTOSEEK, CONST_PERSISTENT | CONST_CS);
128 	REGISTER_LONG_CONSTANT("FTP_USEPASVADDRESS", PHP_FTP_OPT_USEPASVADDRESS, CONST_PERSISTENT | CONST_CS);
129 	REGISTER_LONG_CONSTANT("FTP_FAILED", PHP_FTP_FAILED, CONST_PERSISTENT | CONST_CS);
130 	REGISTER_LONG_CONSTANT("FTP_FINISHED", PHP_FTP_FINISHED, CONST_PERSISTENT | CONST_CS);
131 	REGISTER_LONG_CONSTANT("FTP_MOREDATA", PHP_FTP_MOREDATA, CONST_PERSISTENT | CONST_CS);
132 	return SUCCESS;
133 }
134 
PHP_MINFO_FUNCTION(ftp)135 PHP_MINFO_FUNCTION(ftp)
136 {
137 	php_info_print_table_start();
138 	php_info_print_table_row(2, "FTP support", "enabled");
139 #ifdef HAVE_FTP_SSL
140 	php_info_print_table_row(2, "FTPS support", "enabled");
141 #else
142 	php_info_print_table_row(2, "FTPS support", "disabled");
143 #endif
144 	php_info_print_table_end();
145 }
146 
147 #define	XTYPE(xtype, mode)	{ \
148 	if (mode != FTPTYPE_ASCII && mode != FTPTYPE_IMAGE) { \
149 		zend_argument_value_error(4, "must be either FTP_ASCII or FTP_BINARY"); \
150 		RETURN_THROWS(); \
151 	} \
152 	xtype = mode; \
153 }
154 
155 
156 /* {{{ Opens a FTP stream */
PHP_FUNCTION(ftp_connect)157 PHP_FUNCTION(ftp_connect)
158 {
159 	ftpbuf_t	*ftp;
160 	char		*host;
161 	size_t		host_len;
162 	zend_long 		port = 0;
163 	zend_long		timeout_sec = FTP_DEFAULT_TIMEOUT;
164 
165 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
166 		RETURN_THROWS();
167 	}
168 
169 	if (timeout_sec <= 0) {
170 		zend_argument_value_error(3, "must be greater than 0");
171 		RETURN_THROWS();
172 	}
173 
174 	/* connect */
175 	if (!(ftp = ftp_open(host, (short)port, timeout_sec))) {
176 		RETURN_FALSE;
177 	}
178 
179 	/* autoseek for resuming */
180 	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;
181 	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS;
182 #ifdef HAVE_FTP_SSL
183 	/* disable ssl */
184 	ftp->use_ssl = 0;
185 #endif
186 
187 	object_init_ex(return_value, php_ftp_ce);
188 	ftp_object_from_zend_object(Z_OBJ_P(return_value))->ftp = ftp;
189 }
190 /* }}} */
191 
192 #ifdef HAVE_FTP_SSL
193 /* {{{ Opens a FTP-SSL stream */
PHP_FUNCTION(ftp_ssl_connect)194 PHP_FUNCTION(ftp_ssl_connect)
195 {
196 	ftpbuf_t	*ftp;
197 	char		*host;
198 	size_t		host_len;
199 	zend_long		port = 0;
200 	zend_long		timeout_sec = FTP_DEFAULT_TIMEOUT;
201 
202 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
203 		RETURN_THROWS();
204 	}
205 
206 	if (timeout_sec <= 0) {
207 		zend_argument_value_error(3, "must be greater than 0");
208 		RETURN_THROWS();
209 	}
210 
211 	/* connect */
212 	if (!(ftp = ftp_open(host, (short)port, timeout_sec))) {
213 		RETURN_FALSE;
214 	}
215 
216 	/* autoseek for resuming */
217 	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;
218 	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS;
219 	/* enable ssl */
220 	ftp->use_ssl = 1;
221 
222 	object_init_ex(return_value, php_ftp_ce);
223 	ftp_object_from_zend_object(Z_OBJ_P(return_value))->ftp = ftp;
224 }
225 /* }}} */
226 #endif
227 
228 #define GET_FTPBUF(ftpbuf, zftp) \
229 	ftpbuf = ftp_object_from_zend_object(Z_OBJ_P(zftp))->ftp; \
230 	if (!ftpbuf) { \
231 		zend_throw_exception(zend_ce_value_error, "FTP\\Connection is already closed", 0); \
232 		RETURN_THROWS(); \
233 	}
234 
235 /* {{{ Logs into the FTP server */
PHP_FUNCTION(ftp_login)236 PHP_FUNCTION(ftp_login)
237 {
238 	zval 		*z_ftp;
239 	ftpbuf_t	*ftp;
240 	char *user, *pass;
241 	size_t user_len, pass_len;
242 
243 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss", &z_ftp, php_ftp_ce, &user, &user_len, &pass, &pass_len) == FAILURE) {
244 		RETURN_THROWS();
245 	}
246 	GET_FTPBUF(ftp, z_ftp);
247 
248 	/* log in */
249 	if (!ftp_login(ftp, user, user_len, pass, pass_len)) {
250 		if (*ftp->inbuf) {
251 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
252 		}
253 		RETURN_FALSE;
254 	}
255 
256 	RETURN_TRUE;
257 }
258 /* }}} */
259 
260 /* {{{ Returns the present working directory */
PHP_FUNCTION(ftp_pwd)261 PHP_FUNCTION(ftp_pwd)
262 {
263 	zval 		*z_ftp;
264 	ftpbuf_t	*ftp;
265 	const char	*pwd;
266 
267 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) {
268 		RETURN_THROWS();
269 	}
270 	GET_FTPBUF(ftp, z_ftp);
271 
272 	if (!(pwd = ftp_pwd(ftp))) {
273 		if (*ftp->inbuf) {
274 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
275 		}
276 		RETURN_FALSE;
277 	}
278 
279 	RETURN_STRING((char*) pwd);
280 }
281 /* }}} */
282 
283 /* {{{ Changes to the parent directory */
PHP_FUNCTION(ftp_cdup)284 PHP_FUNCTION(ftp_cdup)
285 {
286 	zval 		*z_ftp;
287 	ftpbuf_t	*ftp;
288 
289 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) {
290 		RETURN_THROWS();
291 	}
292 	GET_FTPBUF(ftp, z_ftp);
293 
294 	if (!ftp_cdup(ftp)) {
295 		if (*ftp->inbuf) {
296 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
297 		}
298 		RETURN_FALSE;
299 	}
300 
301 	RETURN_TRUE;
302 }
303 /* }}} */
304 
305 /* {{{ Changes directories */
PHP_FUNCTION(ftp_chdir)306 PHP_FUNCTION(ftp_chdir)
307 {
308 	zval		*z_ftp;
309 	ftpbuf_t	*ftp;
310 	char		*dir;
311 	size_t			dir_len;
312 
313 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &dir, &dir_len) == FAILURE) {
314 		RETURN_THROWS();
315 	}
316 	GET_FTPBUF(ftp, z_ftp);
317 
318 	/* change directories */
319 	if (!ftp_chdir(ftp, dir, dir_len)) {
320 		if (*ftp->inbuf) {
321 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
322 		}
323 		RETURN_FALSE;
324 	}
325 
326 	RETURN_TRUE;
327 }
328 /* }}} */
329 
330 /* {{{ Requests execution of a program on the FTP server */
PHP_FUNCTION(ftp_exec)331 PHP_FUNCTION(ftp_exec)
332 {
333 	zval		*z_ftp;
334 	ftpbuf_t	*ftp;
335 	char		*cmd;
336 	size_t			cmd_len;
337 
338 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &cmd, &cmd_len) == FAILURE) {
339 		RETURN_THROWS();
340 	}
341 	GET_FTPBUF(ftp, z_ftp);
342 
343 	/* execute serverside command */
344 	if (!ftp_exec(ftp, cmd, cmd_len)) {
345 		if (*ftp->inbuf) {
346 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
347 		}
348 		RETURN_FALSE;
349 	}
350 
351 	RETURN_TRUE;
352 }
353 /* }}} */
354 
355 /* {{{ Sends a literal command to the FTP server */
PHP_FUNCTION(ftp_raw)356 PHP_FUNCTION(ftp_raw)
357 {
358 	zval		*z_ftp;
359 	ftpbuf_t	*ftp;
360 	char		*cmd;
361 	size_t			cmd_len;
362 
363 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &cmd, &cmd_len) == FAILURE) {
364 		RETURN_THROWS();
365 	}
366 	GET_FTPBUF(ftp, z_ftp);
367 
368 	/* execute arbitrary ftp command */
369 	ftp_raw(ftp, cmd, cmd_len, return_value);
370 }
371 /* }}} */
372 
373 /* {{{ Creates a directory and returns the absolute path for the new directory or false on error */
PHP_FUNCTION(ftp_mkdir)374 PHP_FUNCTION(ftp_mkdir)
375 {
376 	zval		*z_ftp;
377 	ftpbuf_t	*ftp;
378 	char		*dir;
379 	zend_string *tmp;
380 	size_t		dir_len;
381 
382 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &dir, &dir_len) == FAILURE) {
383 		RETURN_THROWS();
384 	}
385 	GET_FTPBUF(ftp, z_ftp);
386 
387 	/* create directory */
388 	if (NULL == (tmp = ftp_mkdir(ftp, dir, dir_len))) {
389 		if (*ftp->inbuf) {
390 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
391 		}
392 		RETURN_FALSE;
393 	}
394 
395 	RETURN_STR(tmp);
396 }
397 /* }}} */
398 
399 /* {{{ Removes a directory */
PHP_FUNCTION(ftp_rmdir)400 PHP_FUNCTION(ftp_rmdir)
401 {
402 	zval		*z_ftp;
403 	ftpbuf_t	*ftp;
404 	char		*dir;
405 	size_t		dir_len;
406 
407 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &dir, &dir_len) == FAILURE) {
408 		RETURN_THROWS();
409 	}
410 	GET_FTPBUF(ftp, z_ftp);
411 
412 	/* remove directorie */
413 	if (!ftp_rmdir(ftp, dir, dir_len)) {
414 		if (*ftp->inbuf) {
415 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
416 		}
417 		RETURN_FALSE;
418 	}
419 
420 	RETURN_TRUE;
421 }
422 /* }}} */
423 
424 /* {{{ Sets permissions on a file */
PHP_FUNCTION(ftp_chmod)425 PHP_FUNCTION(ftp_chmod)
426 {
427 	zval		*z_ftp;
428 	ftpbuf_t	*ftp;
429 	char		*filename;
430 	size_t		filename_len;
431 	zend_long		mode;
432 
433 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olp", &z_ftp, php_ftp_ce, &mode, &filename, &filename_len) == FAILURE) {
434 		RETURN_THROWS();
435 	}
436 	GET_FTPBUF(ftp, z_ftp);
437 
438 	if (!ftp_chmod(ftp, mode, filename, filename_len)) {
439 		if (*ftp->inbuf) {
440 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
441 		}
442 		RETURN_FALSE;
443 	}
444 
445 	RETURN_LONG(mode);
446 }
447 /* }}} */
448 
449 /* {{{ Attempt to allocate space on the remote FTP server */
PHP_FUNCTION(ftp_alloc)450 PHP_FUNCTION(ftp_alloc)
451 {
452 	zval		*z_ftp, *zresponse = NULL;
453 	ftpbuf_t	*ftp;
454 	zend_long		size, ret;
455 	zend_string	*response = NULL;
456 
457 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|z", &z_ftp, php_ftp_ce, &size, &zresponse) == FAILURE) {
458 		RETURN_THROWS();
459 	}
460 	GET_FTPBUF(ftp, z_ftp);
461 
462 	ret = ftp_alloc(ftp, size, zresponse ? &response : NULL);
463 
464 	if (response) {
465 		ZEND_TRY_ASSIGN_REF_STR(zresponse, response);
466 	}
467 
468 	if (!ret) {
469 		RETURN_FALSE;
470 	}
471 
472 	RETURN_TRUE;
473 }
474 /* }}} */
475 
476 /* {{{ Returns an array of filenames in the given directory */
PHP_FUNCTION(ftp_nlist)477 PHP_FUNCTION(ftp_nlist)
478 {
479 	zval		*z_ftp;
480 	ftpbuf_t	*ftp;
481 	char		**nlist, **ptr, *dir;
482 	size_t		dir_len;
483 
484 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Op", &z_ftp, php_ftp_ce, &dir, &dir_len) == FAILURE) {
485 		RETURN_THROWS();
486 	}
487 	GET_FTPBUF(ftp, z_ftp);
488 
489 	/* get list of files */
490 	if (NULL == (nlist = ftp_nlist(ftp, dir, dir_len))) {
491 		RETURN_FALSE;
492 	}
493 
494 	array_init(return_value);
495 	for (ptr = nlist; *ptr; ptr++) {
496 		add_next_index_string(return_value, *ptr);
497 	}
498 	efree(nlist);
499 }
500 /* }}} */
501 
502 /* {{{ Returns a detailed listing of a directory as an array of output lines */
PHP_FUNCTION(ftp_rawlist)503 PHP_FUNCTION(ftp_rawlist)
504 {
505 	zval		*z_ftp;
506 	ftpbuf_t	*ftp;
507 	char		**llist, **ptr, *dir;
508 	size_t		dir_len;
509 	bool	recursive = 0;
510 
511 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os|b", &z_ftp, php_ftp_ce, &dir, &dir_len, &recursive) == FAILURE) {
512 		RETURN_THROWS();
513 	}
514 	GET_FTPBUF(ftp, z_ftp);
515 
516 	/* get raw directory listing */
517 	if (NULL == (llist = ftp_list(ftp, dir, dir_len, recursive))) {
518 		RETURN_FALSE;
519 	}
520 
521 	array_init(return_value);
522 	for (ptr = llist; *ptr; ptr++) {
523 		add_next_index_string(return_value, *ptr);
524 	}
525 	efree(llist);
526 }
527 /* }}} */
528 
529 /* {{{ Returns a detailed listing of a directory as an array of parsed output lines */
PHP_FUNCTION(ftp_mlsd)530 PHP_FUNCTION(ftp_mlsd)
531 {
532 	zval		*z_ftp;
533 	ftpbuf_t	*ftp;
534 	char		**llist, **ptr, *dir;
535 	size_t		dir_len;
536 	zval		entry;
537 
538 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &dir, &dir_len) == FAILURE) {
539 		RETURN_THROWS();
540 	}
541 	GET_FTPBUF(ftp, z_ftp);
542 
543 	/* get raw directory listing */
544 	if (NULL == (llist = ftp_mlsd(ftp, dir, dir_len))) {
545 		RETURN_FALSE;
546 	}
547 
548 	array_init(return_value);
549 	for (ptr = llist; *ptr; ptr++) {
550 		array_init(&entry);
551 		if (ftp_mlsd_parse_line(Z_ARRVAL_P(&entry), *ptr) == SUCCESS) {
552 			zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &entry);
553 		} else {
554 			zval_ptr_dtor(&entry);
555 		}
556 	}
557 
558 	efree(llist);
559 }
560 /* }}} */
561 
562 /* {{{ Returns the system type identifier */
PHP_FUNCTION(ftp_systype)563 PHP_FUNCTION(ftp_systype)
564 {
565 	zval		*z_ftp;
566 	ftpbuf_t	*ftp;
567 	const char	*syst;
568 
569 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) {
570 		RETURN_THROWS();
571 	}
572 	GET_FTPBUF(ftp, z_ftp);
573 
574 	if (NULL == (syst = ftp_syst(ftp))) {
575 		if (*ftp->inbuf) {
576 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
577 		}
578 		RETURN_FALSE;
579 	}
580 
581 	RETURN_STRING((char*) syst);
582 }
583 /* }}} */
584 
585 /* {{{ Retrieves a file from the FTP server and writes it to an open file */
PHP_FUNCTION(ftp_fget)586 PHP_FUNCTION(ftp_fget)
587 {
588 	zval		*z_ftp, *z_file;
589 	ftpbuf_t	*ftp;
590 	ftptype_t	xtype;
591 	php_stream	*stream;
592 	char		*file;
593 	size_t		file_len;
594 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
595 
596 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ors|ll", &z_ftp, php_ftp_ce, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
597 		RETURN_THROWS();
598 	}
599 	GET_FTPBUF(ftp, z_ftp);
600 	php_stream_from_res(stream, Z_RES_P(z_file));
601 	XTYPE(xtype, mode);
602 
603 	/* ignore autoresume if autoseek is switched off */
604 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
605 		resumepos = 0;
606 	}
607 
608 	if (ftp->autoseek && resumepos) {
609 		/* if autoresume is wanted seek to end */
610 		if (resumepos == PHP_FTP_AUTORESUME) {
611 			php_stream_seek(stream, 0, SEEK_END);
612 			resumepos = php_stream_tell(stream);
613 		} else {
614 			php_stream_seek(stream, resumepos, SEEK_SET);
615 		}
616 	}
617 
618 	if (!ftp_get(ftp, stream, file, file_len, xtype, resumepos)) {
619 		if (*ftp->inbuf) {
620 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
621 		}
622 		RETURN_FALSE;
623 	}
624 
625 	RETURN_TRUE;
626 }
627 /* }}} */
628 
629 /* {{{ Retrieves a file from the FTP server asynchronly and writes it to an open file */
PHP_FUNCTION(ftp_nb_fget)630 PHP_FUNCTION(ftp_nb_fget)
631 {
632 	zval		*z_ftp, *z_file;
633 	ftpbuf_t	*ftp;
634 	ftptype_t	xtype;
635 	php_stream	*stream;
636 	char		*file;
637 	size_t		file_len;
638 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0, ret;
639 
640 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ors|ll", &z_ftp, php_ftp_ce, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
641 		RETURN_THROWS();
642 	}
643 	GET_FTPBUF(ftp, z_ftp);
644 	php_stream_from_res(stream, Z_RES_P(z_file));
645 	XTYPE(xtype, mode);
646 
647 	/* ignore autoresume if autoseek is switched off */
648 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
649 		resumepos = 0;
650 	}
651 
652 	if (ftp->autoseek && resumepos) {
653 		/* if autoresume is wanted seek to end */
654 		if (resumepos == PHP_FTP_AUTORESUME) {
655 			php_stream_seek(stream, 0, SEEK_END);
656 			resumepos = php_stream_tell(stream);
657 		} else {
658 			php_stream_seek(stream, resumepos, SEEK_SET);
659 		}
660 	}
661 
662 	/* configuration */
663 	ftp->direction = 0;   /* recv */
664 	ftp->closestream = 0; /* do not close */
665 
666 	if ((ret = ftp_nb_get(ftp, stream, file, file_len, xtype, resumepos)) == PHP_FTP_FAILED) {
667 		if (*ftp->inbuf) {
668 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
669 		}
670 		RETURN_LONG(ret);
671 	}
672 
673 	RETURN_LONG(ret);
674 }
675 /* }}} */
676 
677 /* {{{ Turns passive mode on or off */
PHP_FUNCTION(ftp_pasv)678 PHP_FUNCTION(ftp_pasv)
679 {
680 	zval		*z_ftp;
681 	ftpbuf_t	*ftp;
682 	bool	pasv;
683 
684 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &z_ftp, php_ftp_ce, &pasv) == FAILURE) {
685 		RETURN_THROWS();
686 	}
687 	GET_FTPBUF(ftp, z_ftp);
688 
689 	if (!ftp_pasv(ftp, pasv ? 1 : 0)) {
690 		RETURN_FALSE;
691 	}
692 
693 	RETURN_TRUE;
694 }
695 /* }}} */
696 
697 /* {{{ Retrieves a file from the FTP server and writes it to a local file */
PHP_FUNCTION(ftp_get)698 PHP_FUNCTION(ftp_get)
699 {
700 	zval		*z_ftp;
701 	ftpbuf_t	*ftp;
702 	ftptype_t	xtype;
703 	php_stream	*outstream;
704 	char		*local, *remote;
705 	size_t		local_len, remote_len;
706 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
707 
708 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Opp|ll", &z_ftp, php_ftp_ce, &local, &local_len, &remote, &remote_len, &mode, &resumepos) == FAILURE) {
709 		RETURN_THROWS();
710 	}
711 	GET_FTPBUF(ftp, z_ftp);
712 	XTYPE(xtype, mode);
713 
714 	/* ignore autoresume if autoseek is switched off */
715 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
716 		resumepos = 0;
717 	}
718 
719 #ifdef PHP_WIN32
720 	mode = FTPTYPE_IMAGE;
721 #endif
722 
723 	if (ftp->autoseek && resumepos) {
724 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt+" : "rb+", REPORT_ERRORS, NULL);
725 		if (outstream == NULL) {
726 			outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
727 		}
728 		if (outstream != NULL) {
729 			/* if autoresume is wanted seek to end */
730 			if (resumepos == PHP_FTP_AUTORESUME) {
731 				php_stream_seek(outstream, 0, SEEK_END);
732 				resumepos = php_stream_tell(outstream);
733 			} else {
734 				php_stream_seek(outstream, resumepos, SEEK_SET);
735 			}
736 		}
737 	} else {
738 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
739 	}
740 
741 	if (outstream == NULL)	{
742 		php_error_docref(NULL, E_WARNING, "Error opening %s", local);
743 		RETURN_FALSE;
744 	}
745 
746 	if (!ftp_get(ftp, outstream, remote, remote_len, xtype, resumepos)) {
747 		php_stream_close(outstream);
748 		VCWD_UNLINK(local);
749 		if (*ftp->inbuf) {
750 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
751 		}
752 		RETURN_FALSE;
753 	}
754 
755 	php_stream_close(outstream);
756 	RETURN_TRUE;
757 }
758 /* }}} */
759 
760 /* {{{ Retrieves a file from the FTP server nbhronly and writes it to a local file */
PHP_FUNCTION(ftp_nb_get)761 PHP_FUNCTION(ftp_nb_get)
762 {
763 	zval		*z_ftp;
764 	ftpbuf_t	*ftp;
765 	ftptype_t	xtype;
766 	php_stream	*outstream;
767 	char		*local, *remote;
768 	size_t		local_len, remote_len;
769 	int ret;
770 	zend_long		mode=FTPTYPE_IMAGE, resumepos=0;
771 
772 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss|ll", &z_ftp, php_ftp_ce, &local, &local_len, &remote, &remote_len, &mode, &resumepos) == FAILURE) {
773 		RETURN_THROWS();
774 	}
775 	GET_FTPBUF(ftp, z_ftp);
776 	XTYPE(xtype, mode);
777 
778 	/* ignore autoresume if autoseek is switched off */
779 	if (!ftp->autoseek && resumepos == PHP_FTP_AUTORESUME) {
780 		resumepos = 0;
781 	}
782 #ifdef PHP_WIN32
783 	mode = FTPTYPE_IMAGE;
784 #endif
785 	if (ftp->autoseek && resumepos) {
786 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt+" : "rb+", REPORT_ERRORS, NULL);
787 		if (outstream == NULL) {
788 			outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
789 		}
790 		if (outstream != NULL) {
791 			/* if autoresume is wanted seek to end */
792 			if (resumepos == PHP_FTP_AUTORESUME) {
793 				php_stream_seek(outstream, 0, SEEK_END);
794 				resumepos = php_stream_tell(outstream);
795 			} else {
796 				php_stream_seek(outstream, resumepos, SEEK_SET);
797 			}
798 		}
799 	} else {
800 		outstream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "wt" : "wb", REPORT_ERRORS, NULL);
801 	}
802 
803 	if (outstream == NULL)	{
804 		php_error_docref(NULL, E_WARNING, "Error opening %s", local);
805 		RETURN_FALSE;
806 	}
807 
808 	/* configuration */
809 	ftp->direction = 0;   /* recv */
810 	ftp->closestream = 1; /* do close */
811 
812 	if ((ret = ftp_nb_get(ftp, outstream, remote, remote_len, xtype, resumepos)) == PHP_FTP_FAILED) {
813 		php_stream_close(outstream);
814 		ftp->stream = NULL;
815 		VCWD_UNLINK(local);
816 		if (*ftp->inbuf) {
817 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
818 		}
819 		RETURN_LONG(PHP_FTP_FAILED);
820 	}
821 
822 	if (ret == PHP_FTP_FINISHED){
823 		php_stream_close(outstream);
824 		ftp->stream = NULL;
825 	}
826 
827 	RETURN_LONG(ret);
828 }
829 /* }}} */
830 
831 /* {{{ Continues retrieving/sending a file nbronously */
PHP_FUNCTION(ftp_nb_continue)832 PHP_FUNCTION(ftp_nb_continue)
833 {
834 	zval		*z_ftp;
835 	ftpbuf_t	*ftp;
836 	zend_long		ret;
837 
838 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) {
839 		RETURN_THROWS();
840 	}
841 	GET_FTPBUF(ftp, z_ftp);
842 
843 	if (!ftp->nb) {
844 		php_error_docref(NULL, E_WARNING, "No nbronous transfer to continue");
845 		RETURN_LONG(PHP_FTP_FAILED);
846 	}
847 
848 	if (ftp->direction) {
849 		ret=ftp_nb_continue_write(ftp);
850 	} else {
851 		ret=ftp_nb_continue_read(ftp);
852 	}
853 
854 	if (ret != PHP_FTP_MOREDATA && ftp->closestream) {
855 		php_stream_close(ftp->stream);
856 		ftp->stream = NULL;
857 	}
858 
859 	if (ret == PHP_FTP_FAILED) {
860 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
861 	}
862 
863 	RETURN_LONG(ret);
864 }
865 /* }}} */
866 
867 /* {{{ Stores a file from an open file to the FTP server */
PHP_FUNCTION(ftp_fput)868 PHP_FUNCTION(ftp_fput)
869 {
870 	zval		*z_ftp, *z_file;
871 	ftpbuf_t	*ftp;
872 	ftptype_t	xtype;
873 	size_t		remote_len;
874 	zend_long		mode=FTPTYPE_IMAGE, startpos=0;
875 	php_stream	*stream;
876 	char		*remote;
877 
878 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osr|ll", &z_ftp, php_ftp_ce, &remote, &remote_len, &z_file, &mode, &startpos) == FAILURE) {
879 		RETURN_THROWS();
880 	}
881 	GET_FTPBUF(ftp, z_ftp);
882 	php_stream_from_zval(stream, z_file);
883 	XTYPE(xtype, mode);
884 
885 	/* ignore autoresume if autoseek is switched off */
886 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
887 		startpos = 0;
888 	}
889 
890 	if (ftp->autoseek && startpos) {
891 		/* if autoresume is wanted ask for remote size */
892 		if (startpos == PHP_FTP_AUTORESUME) {
893 			startpos = ftp_size(ftp, remote, remote_len);
894 			if (startpos < 0) {
895 				startpos = 0;
896 			}
897 		}
898 		if (startpos) {
899 			php_stream_seek(stream, startpos, SEEK_SET);
900 		}
901 	}
902 
903 	if (!ftp_put(ftp, remote, remote_len, stream, xtype, startpos)) {
904 		if (*ftp->inbuf) {
905 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
906 		}
907 		RETURN_FALSE;
908 	}
909 
910 	RETURN_TRUE;
911 }
912 /* }}} */
913 
914 /* {{{ Stores a file from an open file to the FTP server nbronly */
PHP_FUNCTION(ftp_nb_fput)915 PHP_FUNCTION(ftp_nb_fput)
916 {
917 	zval		*z_ftp, *z_file;
918 	ftpbuf_t	*ftp;
919 	ftptype_t	xtype;
920 	size_t		remote_len;
921 	int             ret;
922 	zend_long	mode=FTPTYPE_IMAGE, startpos=0;
923 	php_stream	*stream;
924 	char		*remote;
925 
926 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osr|ll", &z_ftp, php_ftp_ce, &remote, &remote_len, &z_file, &mode, &startpos) == FAILURE) {
927 		RETURN_THROWS();
928 	}
929 	GET_FTPBUF(ftp, z_ftp);
930 	php_stream_from_res(stream, Z_RES_P(z_file));
931 	XTYPE(xtype, mode);
932 
933 	/* ignore autoresume if autoseek is switched off */
934 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
935 		startpos = 0;
936 	}
937 
938 	if (ftp->autoseek && startpos) {
939 		/* if autoresume is wanted ask for remote size */
940 		if (startpos == PHP_FTP_AUTORESUME) {
941 			startpos = ftp_size(ftp, remote, remote_len);
942 			if (startpos < 0) {
943 				startpos = 0;
944 			}
945 		}
946 		if (startpos) {
947 			php_stream_seek(stream, startpos, SEEK_SET);
948 		}
949 	}
950 
951 	/* configuration */
952 	ftp->direction = 1;   /* send */
953 	ftp->closestream = 0; /* do not close */
954 
955 	if (((ret = ftp_nb_put(ftp, remote, remote_len, stream, xtype, startpos)) == PHP_FTP_FAILED)) {
956 		if (*ftp->inbuf) {
957 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
958 		}
959 		RETURN_LONG(ret);
960 	}
961 
962 	RETURN_LONG(ret);
963 }
964 /* }}} */
965 
966 
967 /* {{{ Stores a file on the FTP server */
PHP_FUNCTION(ftp_put)968 PHP_FUNCTION(ftp_put)
969 {
970 	zval		*z_ftp;
971 	ftpbuf_t	*ftp;
972 	ftptype_t	xtype;
973 	char		*remote, *local;
974 	size_t		remote_len, local_len;
975 	zend_long		mode=FTPTYPE_IMAGE, startpos=0;
976 	php_stream 	*instream;
977 
978 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Opp|ll", &z_ftp, php_ftp_ce, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
979 		RETURN_THROWS();
980 	}
981 	GET_FTPBUF(ftp, z_ftp);
982 	XTYPE(xtype, mode);
983 
984 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
985 		RETURN_FALSE;
986 	}
987 
988 	/* ignore autoresume if autoseek is switched off */
989 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
990 		startpos = 0;
991 	}
992 
993 	if (ftp->autoseek && startpos) {
994 		/* if autoresume is wanted ask for remote size */
995 		if (startpos == PHP_FTP_AUTORESUME) {
996 			startpos = ftp_size(ftp, remote, remote_len);
997 			if (startpos < 0) {
998 				startpos = 0;
999 			}
1000 		}
1001 		if (startpos) {
1002 			php_stream_seek(instream, startpos, SEEK_SET);
1003 		}
1004 	}
1005 
1006 	if (!ftp_put(ftp, remote, remote_len, instream, xtype, startpos)) {
1007 		php_stream_close(instream);
1008 		if (*ftp->inbuf) {
1009 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1010 		}
1011 		RETURN_FALSE;
1012 	}
1013 	php_stream_close(instream);
1014 
1015 	RETURN_TRUE;
1016 }
1017 /* }}} */
1018 
1019 /* {{{ Append content of a file a another file on the FTP server */
PHP_FUNCTION(ftp_append)1020 PHP_FUNCTION(ftp_append)
1021 {
1022 	zval		*z_ftp;
1023 	ftpbuf_t	*ftp;
1024 	ftptype_t	xtype;
1025 	char		*remote, *local;
1026 	size_t		remote_len, local_len;
1027 	zend_long		mode=FTPTYPE_IMAGE;
1028 	php_stream 	*instream;
1029 
1030 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Opp|l", &z_ftp, php_ftp_ce, &remote, &remote_len, &local, &local_len, &mode) == FAILURE) {
1031 		RETURN_THROWS();
1032 	}
1033 	GET_FTPBUF(ftp, z_ftp);
1034 	XTYPE(xtype, mode);
1035 
1036 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
1037 		RETURN_FALSE;
1038 	}
1039 
1040 	if (!ftp_append(ftp, remote, remote_len, instream, xtype)) {
1041 		php_stream_close(instream);
1042 		if (*ftp->inbuf) {
1043 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1044 		}
1045 		RETURN_FALSE;
1046 	}
1047 	php_stream_close(instream);
1048 
1049 	RETURN_TRUE;
1050 }
1051 /* }}} */
1052 
1053 /* {{{ Stores a file on the FTP server */
PHP_FUNCTION(ftp_nb_put)1054 PHP_FUNCTION(ftp_nb_put)
1055 {
1056 	zval		*z_ftp;
1057 	ftpbuf_t	*ftp;
1058 	ftptype_t	xtype;
1059 	char		*remote, *local;
1060 	size_t		remote_len, local_len;
1061 	zend_long		mode=FTPTYPE_IMAGE, startpos=0, ret;
1062 	php_stream 	*instream;
1063 
1064 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Opp|ll", &z_ftp, php_ftp_ce, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
1065 		RETURN_THROWS();
1066 	}
1067 	GET_FTPBUF(ftp, z_ftp);
1068 	XTYPE(xtype, mode);
1069 
1070 	if (!(instream = php_stream_open_wrapper(local, mode == FTPTYPE_ASCII ? "rt" : "rb", REPORT_ERRORS, NULL))) {
1071 		RETURN_FALSE;
1072 	}
1073 
1074 	/* ignore autoresume if autoseek is switched off */
1075 	if (!ftp->autoseek && startpos == PHP_FTP_AUTORESUME) {
1076 		startpos = 0;
1077 	}
1078 
1079 	if (ftp->autoseek && startpos) {
1080 		/* if autoresume is wanted ask for remote size */
1081 		if (startpos == PHP_FTP_AUTORESUME) {
1082 			startpos = ftp_size(ftp, remote, remote_len);
1083 			if (startpos < 0) {
1084 				startpos = 0;
1085 			}
1086 		}
1087 		if (startpos) {
1088 			php_stream_seek(instream, startpos, SEEK_SET);
1089 		}
1090 	}
1091 
1092 	/* configuration */
1093 	ftp->direction = 1;   /* send */
1094 	ftp->closestream = 1; /* do close */
1095 
1096 	ret = ftp_nb_put(ftp, remote, remote_len, instream, xtype, startpos);
1097 
1098 	if (ret != PHP_FTP_MOREDATA) {
1099 		php_stream_close(instream);
1100 		ftp->stream = NULL;
1101 	}
1102 
1103 	if (ret == PHP_FTP_FAILED) {
1104 		php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1105 	}
1106 
1107 	RETURN_LONG(ret);
1108 }
1109 /* }}} */
1110 
1111 /* {{{ Returns the size of the file, or -1 on error */
PHP_FUNCTION(ftp_size)1112 PHP_FUNCTION(ftp_size)
1113 {
1114 	zval		*z_ftp;
1115 	ftpbuf_t	*ftp;
1116 	char		*file;
1117 	size_t		file_len;
1118 
1119 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Op", &z_ftp, php_ftp_ce, &file, &file_len) == FAILURE) {
1120 		RETURN_THROWS();
1121 	}
1122 	GET_FTPBUF(ftp, z_ftp);
1123 
1124 	/* get file size */
1125 	RETURN_LONG(ftp_size(ftp, file, file_len));
1126 }
1127 /* }}} */
1128 
1129 /* {{{ Returns the last modification time of the file, or -1 on error */
PHP_FUNCTION(ftp_mdtm)1130 PHP_FUNCTION(ftp_mdtm)
1131 {
1132 	zval		*z_ftp;
1133 	ftpbuf_t	*ftp;
1134 	char		*file;
1135 	size_t		file_len;
1136 
1137 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Op", &z_ftp, php_ftp_ce, &file, &file_len) == FAILURE) {
1138 		RETURN_THROWS();
1139 	}
1140 	GET_FTPBUF(ftp, z_ftp);
1141 
1142 	/* get file mod time */
1143 	RETURN_LONG(ftp_mdtm(ftp, file, file_len));
1144 }
1145 /* }}} */
1146 
1147 /* {{{ Renames the given file to a new path */
PHP_FUNCTION(ftp_rename)1148 PHP_FUNCTION(ftp_rename)
1149 {
1150 	zval		*z_ftp;
1151 	ftpbuf_t	*ftp;
1152 	char		*src, *dest;
1153 	size_t		src_len, dest_len;
1154 
1155 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss", &z_ftp, php_ftp_ce, &src, &src_len, &dest, &dest_len) == FAILURE) {
1156 		RETURN_THROWS();
1157 	}
1158 	GET_FTPBUF(ftp, z_ftp);
1159 
1160 	/* rename the file */
1161 	if (!ftp_rename(ftp, src, src_len, dest, dest_len)) {
1162 		if (*ftp->inbuf) {
1163 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1164 		}
1165 		RETURN_FALSE;
1166 	}
1167 
1168 	RETURN_TRUE;
1169 }
1170 /* }}} */
1171 
1172 /* {{{ Deletes a file */
PHP_FUNCTION(ftp_delete)1173 PHP_FUNCTION(ftp_delete)
1174 {
1175 	zval		*z_ftp;
1176 	ftpbuf_t	*ftp;
1177 	char		*file;
1178 	size_t		file_len;
1179 
1180 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &file, &file_len) == FAILURE) {
1181 		RETURN_THROWS();
1182 	}
1183 	GET_FTPBUF(ftp, z_ftp);
1184 
1185 	/* delete the file */
1186 	if (!ftp_delete(ftp, file, file_len)) {
1187 		if (*ftp->inbuf) {
1188 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1189 		}
1190 		RETURN_FALSE;
1191 	}
1192 
1193 	RETURN_TRUE;
1194 }
1195 /* }}} */
1196 
1197 /* {{{ Sends a SITE command to the server */
PHP_FUNCTION(ftp_site)1198 PHP_FUNCTION(ftp_site)
1199 {
1200 	zval		*z_ftp;
1201 	ftpbuf_t	*ftp;
1202 	char		*cmd;
1203 	size_t		cmd_len;
1204 
1205 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &z_ftp, php_ftp_ce, &cmd, &cmd_len) == FAILURE) {
1206 		RETURN_THROWS();
1207 	}
1208 	GET_FTPBUF(ftp, z_ftp);
1209 
1210 	/* send the site command */
1211 	if (!ftp_site(ftp, cmd, cmd_len)) {
1212 		if (*ftp->inbuf) {
1213 			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
1214 		}
1215 		RETURN_FALSE;
1216 	}
1217 
1218 	RETURN_TRUE;
1219 }
1220 /* }}} */
1221 
1222 /* {{{ Closes the FTP stream */
PHP_FUNCTION(ftp_close)1223 PHP_FUNCTION(ftp_close)
1224 {
1225 	zval		*z_ftp;
1226 	php_ftp_object *obj;
1227 	bool success = true;
1228 
1229 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) {
1230 		RETURN_THROWS();
1231 	}
1232 
1233 	obj = ftp_object_from_zend_object(Z_OBJ_P(z_ftp));
1234 	if (obj->ftp) {
1235 		success = ftp_quit(obj->ftp);
1236 		ftp_close(obj->ftp);
1237 		obj->ftp = NULL;
1238 	}
1239 
1240 	RETURN_BOOL(success);
1241 }
1242 /* }}} */
1243 
1244 /* {{{ Sets an FTP option */
PHP_FUNCTION(ftp_set_option)1245 PHP_FUNCTION(ftp_set_option)
1246 {
1247 	zval		*z_ftp, *z_value;
1248 	zend_long		option;
1249 	ftpbuf_t	*ftp;
1250 
1251 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &z_ftp, php_ftp_ce, &option, &z_value) == FAILURE) {
1252 		RETURN_THROWS();
1253 	}
1254 	GET_FTPBUF(ftp, z_ftp);
1255 
1256 	switch (option) {
1257 		case PHP_FTP_OPT_TIMEOUT_SEC:
1258 			if (Z_TYPE_P(z_value) != IS_LONG) {
1259 				zend_argument_type_error(3, "must be of type int for the FTP_TIMEOUT_SEC option, %s given", zend_zval_type_name(z_value));
1260 				RETURN_THROWS();
1261 			}
1262 			if (Z_LVAL_P(z_value) <= 0) {
1263 				zend_argument_value_error(3, "must be greater than 0 for the FTP_TIMEOUT_SEC option");
1264 				RETURN_THROWS();
1265 			}
1266 			ftp->timeout_sec = Z_LVAL_P(z_value);
1267 			RETURN_TRUE;
1268 			break;
1269 		case PHP_FTP_OPT_AUTOSEEK:
1270 			if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) {
1271 				zend_argument_type_error(3, "must be of type bool for the FTP_AUTOSEEK option, %s given", zend_zval_type_name(z_value));
1272 				RETURN_THROWS();
1273 			}
1274 			ftp->autoseek = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0;
1275 			RETURN_TRUE;
1276 			break;
1277 		case PHP_FTP_OPT_USEPASVADDRESS:
1278 			if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) {
1279 				zend_argument_type_error(3, "must be of type bool for the FTP_USEPASVADDRESS option, %s given", zend_zval_type_name(z_value));
1280 				RETURN_THROWS();
1281 			}
1282 			ftp->usepasvaddress = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0;
1283 			RETURN_TRUE;
1284 			break;
1285 		default:
1286 			zend_argument_value_error(2, "must be one of FTP_TIMEOUT_SEC, FTP_AUTOSEEK, or FTP_USEPASVADDRESS");
1287 			RETURN_THROWS();
1288 			break;
1289 	}
1290 }
1291 /* }}} */
1292 
1293 /* {{{ Gets an FTP option */
PHP_FUNCTION(ftp_get_option)1294 PHP_FUNCTION(ftp_get_option)
1295 {
1296 	zval		*z_ftp;
1297 	zend_long		option;
1298 	ftpbuf_t	*ftp;
1299 
1300 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &z_ftp, php_ftp_ce, &option) == FAILURE) {
1301 		RETURN_THROWS();
1302 	}
1303 	GET_FTPBUF(ftp, z_ftp);
1304 
1305 	switch (option) {
1306 		case PHP_FTP_OPT_TIMEOUT_SEC:
1307 			RETURN_LONG(ftp->timeout_sec);
1308 			break;
1309 		case PHP_FTP_OPT_AUTOSEEK:
1310 			RETURN_BOOL(ftp->autoseek);
1311 			break;
1312 		case PHP_FTP_OPT_USEPASVADDRESS:
1313 			RETURN_BOOL(ftp->usepasvaddress);
1314 			break;
1315 		default:
1316 			zend_argument_value_error(2, "must be one of FTP_TIMEOUT_SEC, FTP_AUTOSEEK, or FTP_USEPASVADDRESS");
1317 			RETURN_THROWS();
1318 	}
1319 }
1320 /* }}} */
1321 
1322 #endif /* HAVE_FTP */
1323