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