前回、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, '/')); |
(273)