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