前回、Python2で書いたけど、実はアレは実験的な物で、本来はPHPで作られてるシステムで対応したかった。 
  と言うわけで、今回、PHP7.2に機能追加した(更に言えばPHP5.6なんだけど、機能追加なんでここには最新版を置いておく)
  本家に取り込んで欲しいけどまだMLに参加出来てないんで、とりあえずパッチを置いておく。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128  | 
						diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index d1fffc2..5f71d08 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -1744,7 +1744,12 @@ ftp_getdata(ftpbuf_t *ftp)  	/* send the PORT */  	ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;  	ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port; -	arg_len = snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]); +	if(ftp->externalip.s_addr != FTP_DEFAULT_EXTERNALIP){ +		unsigned char *bytes = (unsigned char *)&ftp->externalip.s_addr; +		arg_len = snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", bytes[0], bytes[1], bytes[2], bytes[3], ipbox.c[4], ipbox.c[5]); +	}else{ +		arg_len = snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]); +	}  	if (arg_len < 0) {  		goto bail; diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h index 38e34ac..d0be46a 100644 --- a/ext/ftp/ftp.h +++ b/ext/ftp/ftp.h @@ -32,6 +32,7 @@  #define	FTP_DEFAULT_TIMEOUT	90  #define FTP_DEFAULT_AUTOSEEK 1  #define FTP_DEFAULT_USEPASVADDRESS	1 +#define FTP_DEFAULT_EXTERNALIP	0  #define PHP_FTP_FAILED			0  #define PHP_FTP_FINISHED		1  #define PHP_FTP_MOREDATA		2 @@ -73,6 +74,7 @@ typedef struct ftpbuf  	zend_long	timeout_sec;	/* User configurable timeout (seconds) */  	int			autoseek;	/* User configurable autoseek flag */  	int			usepasvaddress;	/* Use the address returned by the pasv command */ +	struct in_addr externalip;  	int				nb;		/* "nonblocking" transfer in progress */  	databuf_t		*data;	/* Data connection for "nonblocking" transfers */ diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 23c2645..1c112f8 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -340,6 +340,7 @@ PHP_MINIT_FUNCTION(ftp)  	REGISTER_LONG_CONSTANT("FTP_FAILED", PHP_FTP_FAILED, CONST_PERSISTENT | CONST_CS);  	REGISTER_LONG_CONSTANT("FTP_FINISHED", PHP_FTP_FINISHED, CONST_PERSISTENT | CONST_CS);  	REGISTER_LONG_CONSTANT("FTP_MOREDATA", PHP_FTP_MOREDATA, CONST_PERSISTENT | CONST_CS); +	REGISTER_LONG_CONSTANT("FTP_EXTERNALIP", PHP_FTP_OPT_EXTERNALIP, CONST_PERSISTENT | CONST_CS);  	return SUCCESS;  } @@ -373,6 +374,7 @@ PHP_FUNCTION(ftp_connect)  	size_t		host_len;  	zend_long 		port = 0;  	zend_long		timeout_sec = FTP_DEFAULT_TIMEOUT; +	struct in_addr externalip;  	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {  		return; @@ -391,6 +393,7 @@ PHP_FUNCTION(ftp_connect)  	/* autoseek for resuming */  	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;  	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS; +	ftp->externalip.s_addr = FTP_DEFAULT_EXTERNALIP;  #ifdef HAVE_FTP_SSL  	/* disable ssl */  	ftp->use_ssl = 0; @@ -428,6 +431,7 @@ PHP_FUNCTION(ftp_ssl_connect)  	/* autoseek for resuming */  	ftp->autoseek = FTP_DEFAULT_AUTOSEEK;  	ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS; +	ftp->externalip.s_addr = FTP_DEFAULT_EXTERNALIP;  	/* enable ssl */  	ftp->use_ssl = 1; @@ -1572,6 +1576,21 @@ PHP_FUNCTION(ftp_set_option)  			ftp->usepasvaddress = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0;  			RETURN_TRUE;  			break; +		case PHP_FTP_OPT_EXTERNALIP: +			if (Z_TYPE_P(z_value) == IS_STRING) { +				struct in_addr ip; +				if(inet_aton(Z_STRVAL_P(z_value), &ip)!=1){ +					ftp->externalip.s_addr = FTP_DEFAULT_EXTERNALIP; +					RETURN_FALSE; +				}else{ +					ftp->externalip = ip; +					RETURN_TRUE; +				} +			}else{ +				ftp->externalip.s_addr = FTP_DEFAULT_EXTERNALIP; +				RETURN_FALSE; +			} +			break;  		default:  			php_error_docref(NULL, E_WARNING, "Unknown option '" ZEND_LONG_FMT "'", option);  			RETURN_FALSE; @@ -1596,6 +1615,8 @@ PHP_FUNCTION(ftp_get_option)  		RETURN_FALSE;  	} +	char returnbuffer[18]; +	unsigned char *bytes = (unsigned char *) &ftp->externalip.s_addr;  	switch (option) {  		case PHP_FTP_OPT_TIMEOUT_SEC:  			RETURN_LONG(ftp->timeout_sec); @@ -1606,6 +1627,10 @@ PHP_FUNCTION(ftp_get_option)  		case PHP_FTP_OPT_USEPASVADDRESS:  			RETURN_BOOL(ftp->usepasvaddress);  			break; +		case PHP_FTP_OPT_EXTERNALIP: +			snprintf(returnbuffer, sizeof(returnbuffer), "%d.%d.%d.%d",bytes[0],bytes[1],bytes[2],bytes[3]); +			RETURN_STRING(returnbuffer); +			break;  		default:  			php_error_docref(NULL, E_WARNING, "Unknown option '" ZEND_LONG_FMT "'", option);  			RETURN_FALSE; diff --git a/ext/ftp/php_ftp.h b/ext/ftp/php_ftp.h index 3927738..4642517 100644 --- a/ext/ftp/php_ftp.h +++ b/ext/ftp/php_ftp.h @@ -33,6 +33,7 @@ extern zend_module_entry php_ftp_module_entry;  #define PHP_FTP_OPT_TIMEOUT_SEC	0  #define PHP_FTP_OPT_AUTOSEEK	1  #define PHP_FTP_OPT_USEPASVADDRESS	2 +#define PHP_FTP_OPT_EXTERNALIP	3  #define PHP_FTP_AUTORESUME		-1  PHP_MINIT_FUNCTION(ftp);  | 
					
 標準のFTP関数のftp_set_optionで設定できるようにしてみた。
  ftp_set_option(connection, FTP_OPT_EXTERNALIP, public ip address) みたいな感じ。
  解除する場合は、第3引数に0.0.0.0とか設定してやれば従来通りの動作に戻る(正しいIPv4でない値が来た場合もftp_set_option内部で0.0.0.0に設定)
  パッチ当ては、php-srcのディレクトリでpatch -p1 < patchfile
AWSでの使用例
| 
					 1 2 3 4 5 6 7 8 9  | 
						$DEST = ftphost; $USER = ftpuser; $PASS = ftppassword; $c = ftp_connect($DEST); ftp_login($c,$USER,$PASS); $publicip = file_get_contents("http://169.254.169.254/latest/meta-data/public-ipv4"); ftp_set_option($c, FTP_EXTERNALIP, $publicip); var_dump(ftp_nlist($c, '/'));  | 
					
(280)
								