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