File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard / exec.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:32:05 2013 UTC (10 years, 11 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2013 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:    | Author: Rasmus Lerdorf <rasmus@php.net>                              |
   16:    |         Ilia Alshanetsky <iliaa@php.net>                             |
   17:    +----------------------------------------------------------------------+
   18:  */
   19: /* $Id: exec.c,v 1.1.1.3 2013/07/22 01:32:05 misho Exp $ */
   20: 
   21: #include <stdio.h>
   22: #include "php.h"
   23: #include <ctype.h>
   24: #include "php_string.h"
   25: #include "ext/standard/head.h"
   26: #include "ext/standard/file.h"
   27: #include "basic_functions.h"
   28: #include "exec.h"
   29: #include "php_globals.h"
   30: #include "SAPI.h"
   31: 
   32: #if HAVE_SYS_WAIT_H
   33: #include <sys/wait.h>
   34: #endif
   35: #if HAVE_SIGNAL_H
   36: #include <signal.h>
   37: #endif
   38: 
   39: #if HAVE_SYS_TYPES_H
   40: #include <sys/types.h>
   41: #endif
   42: #if HAVE_SYS_STAT_H
   43: #include <sys/stat.h>
   44: #endif
   45: #if HAVE_FCNTL_H
   46: #include <fcntl.h>
   47: #endif
   48: 
   49: #if HAVE_NICE && HAVE_UNISTD_H
   50: #include <unistd.h>
   51: #endif
   52: 
   53: /* {{{ php_exec
   54:  * If type==0, only last line of output is returned (exec)
   55:  * If type==1, all lines will be printed and last lined returned (system)
   56:  * If type==2, all lines will be saved to given array (exec with &$array)
   57:  * If type==3, output will be printed binary, no lines will be saved or returned (passthru)
   58:  *
   59:  */
   60: PHPAPI int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_DC)
   61: {
   62: 	FILE *fp;
   63: 	char *buf;
   64: 	int l = 0, pclose_return;
   65: 	char *b, *d=NULL;
   66: 	php_stream *stream;
   67: 	size_t buflen, bufl = 0;
   68: #if PHP_SIGCHILD
   69: 	void (*sig_handler)() = NULL;
   70: #endif
   71: 
   72: #if PHP_SIGCHILD
   73: 	sig_handler = signal (SIGCHLD, SIG_DFL);
   74: #endif
   75: 
   76: #ifdef PHP_WIN32
   77: 	fp = VCWD_POPEN(cmd, "rb");
   78: #else
   79: 	fp = VCWD_POPEN(cmd, "r");
   80: #endif
   81: 	if (!fp) {
   82: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd);
   83: 		goto err;
   84: 	}
   85: 
   86: 	stream = php_stream_fopen_from_pipe(fp, "rb");
   87: 
   88: 	buf = (char *) emalloc(EXEC_INPUT_BUF);
   89: 	buflen = EXEC_INPUT_BUF;
   90: 
   91: 	if (type != 3) {
   92: 		b = buf;
   93: 		
   94: 		while (php_stream_get_line(stream, b, EXEC_INPUT_BUF, &bufl)) {
   95: 			/* no new line found, let's read some more */
   96: 			if (b[bufl - 1] != '\n' && !php_stream_eof(stream)) {
   97: 				if (buflen < (bufl + (b - buf) + EXEC_INPUT_BUF)) {
   98: 					bufl += b - buf;
   99: 					buflen = bufl + EXEC_INPUT_BUF;
  100: 					buf = erealloc(buf, buflen);
  101: 					b = buf + bufl;
  102: 				} else {
  103: 					b += bufl;
  104: 				}
  105: 				continue;
  106: 			} else if (b != buf) {
  107: 				bufl += b - buf;
  108: 			}
  109: 
  110: 			if (type == 1) {
  111: 				PHPWRITE(buf, bufl);
  112: 				if (php_output_get_level(TSRMLS_C) < 1) {
  113: 					sapi_flush(TSRMLS_C);
  114: 				}
  115: 			} else if (type == 2) {
  116: 				/* strip trailing whitespaces */
  117: 				l = bufl;
  118: 				while (l-- && isspace(((unsigned char *)buf)[l]));
  119: 				if (l != (int)(bufl - 1)) {
  120: 					bufl = l + 1;
  121: 					buf[bufl] = '\0';
  122: 				}
  123: 				add_next_index_stringl(array, buf, bufl, 1);
  124: 			}
  125: 			b = buf;
  126: 		}
  127: 		if (bufl) {
  128: 			/* strip trailing whitespaces if we have not done so already */
  129: 			if ((type == 2 && buf != b) || type != 2) {
  130: 				l = bufl;
  131: 				while (l-- && isspace(((unsigned char *)buf)[l]));
  132: 				if (l != (int)(bufl - 1)) {
  133: 					bufl = l + 1;
  134: 					buf[bufl] = '\0';
  135: 				}
  136: 				if (type == 2) {
  137: 					add_next_index_stringl(array, buf, bufl, 1);
  138: 				}
  139: 			}
  140: 
  141: 			/* Return last line from the shell command */
  142: 			RETVAL_STRINGL(buf, bufl, 1);
  143: 		} else { /* should return NULL, but for BC we return "" */
  144: 			RETVAL_EMPTY_STRING();
  145: 		}
  146: 	} else {
  147: 		while((bufl = php_stream_read(stream, buf, EXEC_INPUT_BUF)) > 0) {
  148: 			PHPWRITE(buf, bufl);
  149: 		}
  150: 	}
  151: 
  152: 	pclose_return = php_stream_close(stream);
  153: 	efree(buf);
  154: 
  155: done:
  156: #if PHP_SIGCHILD
  157: 	if (sig_handler) {
  158: 		signal(SIGCHLD, sig_handler);
  159: 	}
  160: #endif
  161: 	if (d) {
  162: 		efree(d);
  163: 	}
  164: 	return pclose_return;
  165: err:
  166: 	pclose_return = -1;
  167: 	goto done;
  168: }
  169: /* }}} */
  170: 
  171: static void php_exec_ex(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
  172: {
  173: 	char *cmd;
  174: 	int cmd_len;
  175: 	zval *ret_code=NULL, *ret_array=NULL;
  176: 	int ret;
  177: 
  178: 	if (mode) {
  179: 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/", &cmd, &cmd_len, &ret_code) == FAILURE) {
  180: 			RETURN_FALSE;
  181: 		}
  182: 	} else {
  183: 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/z/", &cmd, &cmd_len, &ret_array, &ret_code) == FAILURE) {
  184: 			RETURN_FALSE;
  185: 		}
  186: 	}
  187: 	if (!cmd_len) {
  188: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot execute a blank command");
  189: 		RETURN_FALSE;
  190: 	}
  191: 
  192: 	if (!ret_array) {
  193: 		ret = php_exec(mode, cmd, NULL, return_value TSRMLS_CC);
  194: 	} else {
  195: 		if (Z_TYPE_P(ret_array) != IS_ARRAY) {
  196: 			zval_dtor(ret_array);
  197: 			array_init(ret_array);
  198: 		}
  199: 		ret = php_exec(2, cmd, ret_array, return_value TSRMLS_CC);
  200: 	}
  201: 	if (ret_code) {
  202: 		zval_dtor(ret_code);
  203: 		ZVAL_LONG(ret_code, ret);
  204: 	}
  205: }
  206: /* }}} */
  207: 
  208: /* {{{ proto string exec(string command [, array &output [, int &return_value]])
  209:    Execute an external program */
  210: PHP_FUNCTION(exec)
  211: {
  212: 	php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  213: }
  214: /* }}} */
  215: 
  216: /* {{{ proto int system(string command [, int &return_value])
  217:    Execute an external program and display output */
  218: PHP_FUNCTION(system)
  219: {
  220: 	php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  221: }
  222: /* }}} */
  223: 
  224: /* {{{ proto void passthru(string command [, int &return_value])
  225:    Execute an external program and display raw output */
  226: PHP_FUNCTION(passthru)
  227: {
  228: 	php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
  229: }
  230: /* }}} */
  231: 
  232: /* {{{ php_escape_shell_cmd
  233:    Escape all chars that could possibly be used to
  234:    break out of a shell command
  235: 
  236:    This function emalloc's a string and returns the pointer.
  237:    Remember to efree it when done with it.
  238: 
  239:    *NOT* safe for binary strings
  240: */
  241: PHPAPI char *php_escape_shell_cmd(char *str)
  242: {
  243: 	register int x, y, l = strlen(str);
  244: 	char *cmd;
  245: 	char *p = NULL;
  246: 	size_t estimate = (2 * l) + 1;
  247: 
  248: 	TSRMLS_FETCH();
  249: 
  250: 	cmd = safe_emalloc(2, l, 1);
  251: 
  252: 	for (x = 0, y = 0; x < l; x++) {
  253: 		int mb_len = php_mblen(str + x, (l - x));
  254: 
  255: 		/* skip non-valid multibyte characters */
  256: 		if (mb_len < 0) {
  257: 			continue;
  258: 		} else if (mb_len > 1) {
  259: 			memcpy(cmd + y, str + x, mb_len);
  260: 			y += mb_len;
  261: 			x += mb_len - 1;
  262: 			continue;
  263: 		}
  264: 
  265: 		switch (str[x]) {
  266: #ifndef PHP_WIN32
  267: 			case '"':
  268: 			case '\'':
  269: 				if (!p && (p = memchr(str + x + 1, str[x], l - x - 1))) {
  270: 					/* noop */
  271: 				} else if (p && *p == str[x]) {
  272: 					p = NULL;
  273: 				} else {
  274: 					cmd[y++] = '\\';
  275: 				}
  276: 				cmd[y++] = str[x];
  277: 				break;
  278: #else
  279: 			/* % is Windows specific for enviromental variables, ^%PATH% will 
  280: 				output PATH whil ^%PATH^% not. escapeshellcmd will escape all %.
  281: 			*/
  282: 			case '%':
  283: 			case '"':
  284: 			case '\'':
  285: #endif
  286: 			case '#': /* This is character-set independent */
  287: 			case '&':
  288: 			case ';':
  289: 			case '`':
  290: 			case '|':
  291: 			case '*':
  292: 			case '?':
  293: 			case '~':
  294: 			case '<':
  295: 			case '>':
  296: 			case '^':
  297: 			case '(':
  298: 			case ')':
  299: 			case '[':
  300: 			case ']':
  301: 			case '{':
  302: 			case '}':
  303: 			case '$':
  304: 			case '\\':
  305: 			case '\x0A': /* excluding these two */
  306: 			case '\xFF':
  307: #ifdef PHP_WIN32
  308: 				cmd[y++] = '^';
  309: #else
  310: 				cmd[y++] = '\\';
  311: #endif
  312: 				/* fall-through */
  313: 			default:
  314: 				cmd[y++] = str[x];
  315: 
  316: 		}
  317: 	}
  318: 	cmd[y] = '\0';
  319: 
  320: 	if ((estimate - y) > 4096) {
  321: 		/* realloc if the estimate was way overill
  322: 		 * Arbitrary cutoff point of 4096 */
  323: 		cmd = erealloc(cmd, y + 1);
  324: 	}
  325: 
  326: 	return cmd;
  327: }
  328: /* }}} */
  329: 
  330: /* {{{ php_escape_shell_arg
  331:  */
  332: PHPAPI char *php_escape_shell_arg(char *str)
  333: {
  334: 	int x, y = 0, l = strlen(str);
  335: 	char *cmd;
  336: 	size_t estimate = (4 * l) + 3;
  337: 
  338: 	TSRMLS_FETCH();
  339: 
  340: 	cmd = safe_emalloc(4, l, 3); /* worst case */
  341: 
  342: #ifdef PHP_WIN32
  343: 	cmd[y++] = '"';
  344: #else
  345: 	cmd[y++] = '\'';
  346: #endif
  347: 
  348: 	for (x = 0; x < l; x++) {
  349: 		int mb_len = php_mblen(str + x, (l - x));
  350: 
  351: 		/* skip non-valid multibyte characters */
  352: 		if (mb_len < 0) {
  353: 			continue;
  354: 		} else if (mb_len > 1) {
  355: 			memcpy(cmd + y, str + x, mb_len);
  356: 			y += mb_len;
  357: 			x += mb_len - 1;
  358: 			continue;
  359: 		}
  360: 
  361: 		switch (str[x]) {
  362: #ifdef PHP_WIN32
  363: 		case '"':
  364: 		case '%':
  365: 			cmd[y++] = ' ';
  366: 			break;
  367: #else
  368: 		case '\'':
  369: 			cmd[y++] = '\'';
  370: 			cmd[y++] = '\\';
  371: 			cmd[y++] = '\'';
  372: #endif
  373: 			/* fall-through */
  374: 		default:
  375: 			cmd[y++] = str[x];
  376: 		}
  377: 	}
  378: #ifdef PHP_WIN32
  379: 	cmd[y++] = '"';
  380: #else
  381: 	cmd[y++] = '\'';
  382: #endif
  383: 	cmd[y] = '\0';
  384: 
  385: 	if ((estimate - y) > 4096) {
  386: 		/* realloc if the estimate was way overill
  387: 		 * Arbitrary cutoff point of 4096 */
  388: 		cmd = erealloc(cmd, y + 1);
  389: 	}
  390: 	return cmd;
  391: }
  392: /* }}} */
  393: 
  394: /* {{{ proto string escapeshellcmd(string command)
  395:    Escape shell metacharacters */
  396: PHP_FUNCTION(escapeshellcmd)
  397: {
  398: 	char *command;
  399: 	int command_len;
  400: 	char *cmd = NULL;
  401: 
  402: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &command, &command_len) == FAILURE) {
  403: 		return;
  404: 	}
  405: 
  406: 	if (command_len) {
  407: 		cmd = php_escape_shell_cmd(command);
  408: 		RETVAL_STRING(cmd, 0);
  409: 	} else {
  410: 		RETVAL_EMPTY_STRING();
  411: 	}
  412: }
  413: /* }}} */
  414: 
  415: /* {{{ proto string escapeshellarg(string arg)
  416:    Quote and escape an argument for use in a shell command */
  417: PHP_FUNCTION(escapeshellarg)
  418: {
  419: 	char *argument;
  420: 	int argument_len;
  421: 	char *cmd = NULL;
  422: 
  423: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &argument, &argument_len) == FAILURE) {
  424: 		return;
  425: 	}
  426: 
  427: 	if (argument) {
  428: 		cmd = php_escape_shell_arg(argument);
  429: 		RETVAL_STRING(cmd, 0);
  430: 	}
  431: }
  432: /* }}} */
  433: 
  434: /* {{{ proto string shell_exec(string cmd)
  435:    Execute command via shell and return complete output as string */
  436: PHP_FUNCTION(shell_exec)
  437: {
  438: 	FILE *in;
  439: 	size_t total_readbytes;
  440: 	char *command;
  441: 	int command_len;
  442: 	char *ret;
  443: 	php_stream *stream;
  444: 
  445: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &command, &command_len) == FAILURE) {
  446: 		return;
  447: 	}
  448: 
  449: #ifdef PHP_WIN32
  450: 	if ((in=VCWD_POPEN(command, "rt"))==NULL) {
  451: #else
  452: 	if ((in=VCWD_POPEN(command, "r"))==NULL) {
  453: #endif
  454: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute '%s'", command);
  455: 		RETURN_FALSE;
  456: 	}
  457: 
  458: 	stream = php_stream_fopen_from_pipe(in, "rb");
  459: 	total_readbytes = php_stream_copy_to_mem(stream, &ret, PHP_STREAM_COPY_ALL, 0);
  460: 	php_stream_close(stream);
  461: 
  462: 	if (total_readbytes > 0) {
  463: 		RETVAL_STRINGL(ret, total_readbytes, 0);
  464: 	}
  465: }
  466: /* }}} */
  467: 
  468: #ifdef HAVE_NICE
  469: /* {{{ proto bool proc_nice(int priority)
  470:    Change the priority of the current process */
  471: PHP_FUNCTION(proc_nice)
  472: {
  473: 	long pri;
  474: 
  475: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pri) == FAILURE) {
  476: 		RETURN_FALSE;
  477: 	}
  478: 
  479: 	errno = 0;
  480: 	php_ignore_value(nice(pri));
  481: 	if (errno) {
  482: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only a super user may attempt to increase the priority of a process");
  483: 		RETURN_FALSE;
  484: 	}
  485: 
  486: 	RETURN_TRUE;
  487: }
  488: /* }}} */
  489: #endif
  490: 
  491: /*
  492:  * Local variables:
  493:  * tab-width: 4
  494:  * c-basic-offset: 4
  495:  * End:
  496:  * vim600: sw=4 ts=4 fdm=marker
  497:  * vim<600: sw=4 ts=4
  498:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>