Esempio n. 1
0
/* {{{ PHPAPI char *php_std_date(time_t t TSRMLS_DC)
   Return date string in standard format for http headers */
PHPAPI char *php_std_date(time_t t TSRMLS_DC)
{
	struct tm *tm1, tmbuf;
	char *str;

	tm1 = php_gmtime_r(&t, &tmbuf);
	str = emalloc(81);
	str[0] = '\0';

	if (!tm1) {
		return str;
	}

	if (PG(y2k_compliance)) {
		snprintf(str, 80, "%s, %02d %s %04d %02d:%02d:%02d GMT",
				day_short_names[tm1->tm_wday],
				tm1->tm_mday,
				mon_short_names[tm1->tm_mon],
				tm1->tm_year + 1900,
				tm1->tm_hour, tm1->tm_min, tm1->tm_sec);
	} else {
		snprintf(str, 80, "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
				day_full_names[tm1->tm_wday],
				tm1->tm_mday,
				mon_short_names[tm1->tm_mon],
				((tm1->tm_year) % 100),
				tm1->tm_hour, tm1->tm_min, tm1->tm_sec);
	}

	str[79] = 0;
	return (str);
}
Esempio n. 2
0
/* {{{ char *http_date(time_t) */
PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC)
{
    char *date = NULL;
    struct tm *gmtime, tmbuf;

    if ((gmtime = php_gmtime_r(&t, &tmbuf))) {
        spprintf(&date, 0,
                 "%s, %02d %s %04d %02d:%02d:%02d GMT",
                 days[gmtime->tm_wday], gmtime->tm_mday,
                 months[gmtime->tm_mon], gmtime->tm_year + 1900,
                 gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec
                );
    }

    return date;
}
Esempio n. 3
0
/* {{{ ftp_mdtm
 */
time_t
ftp_mdtm(ftpbuf_t *ftp, const char *path)
{
	time_t		stamp;
	struct tm	*gmt, tmbuf;
	struct tm	tm;
	char		*ptr;
	int		n;

	if (ftp == NULL) {
		return -1;
	}
	if (!ftp_putcmd(ftp, "MDTM", path)) {
		return -1;
	}
	if (!ftp_getresp(ftp) || ftp->resp != 213) {
		return -1;
	}
	/* parse out the timestamp */
	for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
	n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
	if (n != 6) {
		return -1;
	}
	tm.tm_year -= 1900;
	tm.tm_mon--;
	tm.tm_isdst = -1;

	/* figure out the GMT offset */
	stamp = time(NULL);
	gmt = php_gmtime_r(&stamp, &tmbuf);
	if (!gmt) {
		return -1;
	}
	gmt->tm_isdst = -1;

	/* apply the GMT offset */
	tm.tm_sec += stamp - mktime(gmt);
	tm.tm_isdst = gmt->tm_isdst;

	stamp = mktime(&tm);

	return stamp;
}
Esempio n. 4
0
/* {{{ PHPAPI char *php_std_date(time_t t)
   Return date string in standard format for http headers */
PHPAPI char *php_std_date(time_t t)
{
	struct tm *tm1, tmbuf;
	char *str;

	tm1 = php_gmtime_r(&t, &tmbuf);
	str = emalloc(81);
	str[0] = '\0';

	if (!tm1) {
		return str;
	}

	snprintf(str, 80, "%s, %02d %s %04d %02d:%02d:%02d GMT",
			day_short_names[tm1->tm_wday],
			tm1->tm_mday,
			mon_short_names[tm1->tm_mon],
			tm1->tm_year + 1900,
			tm1->tm_hour, tm1->tm_min, tm1->tm_sec);

	str[79] = 0;
	return (str);
}
Esempio n. 5
0
/*	time_t parse_date(char *)
	Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, <*****@*****.**>, et al. */
static inline time_t parse_date(const char *date)
{
    time_t t = 0;
    int tz_offset = -1, year = -1, month = -1, monthday = -1, weekday = -1,
        hours = -1, minutes = -1, seconds = -1;
    struct tm tm;
    enum assume_next dignext = DATE_MDAY;
    const char *indate = date;

    int part = 0; /* max 6 parts */

    while (*date && (part < 6)) {
        int found = 0;

        while (*date && !HTTP_IS_CTYPE(alnum, *date)) {
            date++;
        }

        if (HTTP_IS_CTYPE(alpha, *date)) {
            /* a name coming up */
            char buf[32] = "";
            size_t len;
            sscanf(date, "%31[A-Za-z]", buf);
            len = strlen(buf);

            if (weekday == -1) {
                weekday = check_day(buf, len);
                if (weekday != -1) {
                    found = 1;
                }
            }

            if (!found && (month == -1)) {
                month = check_month(buf);
                if (month != -1) {
                    found = 1;
                }
            }

            if (!found && (tz_offset == -1)) {
                /* this just must be a time zone string */
                tz_offset = check_tzone(buf);
                if (tz_offset != -1) {
                    found = 1;
                }
            }

            if (!found) {
                return -1; /* bad string */
            }
            date += len;
        }
        else if (HTTP_IS_CTYPE(digit, *date)) {
            /* a digit */
            int val;
            char *end;
            if ((seconds == -1) &&
                    (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) {
                /* time stamp! */
                date += 8;
                found = 1;
            }
            else {
                val = (int) strtol(date, &end, 10);

                if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) &&
                        (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) {
                    /* four digits and a value less than 1300 and it is preceeded with
                    a plus or minus. This is a time zone indication. */
                    found = 1;
                    tz_offset = (val / 100 * 60 + val % 100) * 60;

                    /* the + and - prefix indicates the local time compared to GMT,
                    this we need ther reversed math to get what we want */
                    tz_offset = date[-1] == '+' ? -tz_offset : tz_offset;
                }

                if (((end - date) == 8) && (year == -1) && (month == -1) && (monthday == -1)) {
                    /* 8 digits, no year, month or day yet. This is YYYYMMDD */
                    found = 1;
                    year = val / 10000;
                    month = (val % 10000) / 100 - 1; /* month is 0 - 11 */
                    monthday = val % 100;
                }

                if (!found && (dignext == DATE_MDAY) && (monthday == -1)) {
                    if ((val > 0) && (val < 32)) {
                        monthday = val;
                        found = 1;
                    }
                    dignext = DATE_YEAR;
                }

                if (!found && (dignext == DATE_YEAR) && (year == -1)) {
                    year = val;
                    found = 1;
                    if (year < 1900) {
                        year += year > 70 ? 1900 : 2000;
                    }
                    if(monthday == -1) {
                        dignext = DATE_MDAY;
                    }
                }

                if (!found) {
                    return -1;
                }

                date = end;
            }
        }

        part++;
    }

    if (-1 == seconds) {
        seconds = minutes = hours = 0; /* no time, make it zero */
    }

    if ((-1 == monthday) || (-1 == month) || (-1 == year)) {
        /* lacks vital info, fail */
        return -1;
    }

    if (sizeof(time_t) < 5) {
        /* 32 bit time_t can only hold dates to the beginning of 2038 */
        if (year > 2037) {
            return 0x7fffffff;
        }
    }

    tm.tm_sec = seconds;
    tm.tm_min = minutes;
    tm.tm_hour = hours;
    tm.tm_mday = monthday;
    tm.tm_mon = month;
    tm.tm_year = year - 1900;
    tm.tm_wday = 0;
    tm.tm_yday = 0;
    tm.tm_isdst = 0;

    t = mktime(&tm);

    /* time zone adjust */
    if (t != -1) {
        struct tm *gmt, keeptime2;
        long delta;
        time_t t2;

        if((gmt = php_gmtime_r(&t, &keeptime2))) {
            tm = *gmt; /* MSVC quirks */
        } else {
            return -1; /* illegal date/time */
        }

        t2 = mktime(&tm);

        /* Add the time zone diff (between the given timezone and GMT) and the
        diff between the local time zone and GMT. */
        delta = (tz_offset != -1 ? tz_offset : 0) + (t - t2);

        if((delta > 0) && (t + delta < t)) {
            return -1; /* time_t overflow */
        }

        t += delta;
    }

    return t;
}
Esempio n. 6
0
PHP_SUHOSIN_API void suhosin_log(int loglevel, char *fmt, ...)
{
	int s, r, i=0, fd;
	long written, towrite;
	int getcaller=0;
	char *wbuf;
	struct timeval tv;
	time_t now;
	struct tm tm;
#if defined(AF_UNIX)
	struct sockaddr_un saun;
#endif
#ifdef PHP_WIN32
	LPTSTR strs[2];
	unsigned short etype;
	DWORD evid;
#endif
	char buf[5000];
	char error[5000];
	char *ip_address;
	char *fname;
	char *alertstring;
	int lineno;
	va_list ap;
	TSRMLS_FETCH();

#if PHP_VERSION_ID >= 50500
	getcaller = (loglevel & S_GETCALLER) == S_GETCALLER;
#endif
	/* remove the S_GETCALLER flag */
	loglevel = loglevel & ~S_GETCALLER;

	SDEBUG("(suhosin_log) loglevel: %d log_syslog: %u - log_sapi: %u - log_script: %u", loglevel, SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script));

	/* dump core if wanted */
	if (SUHOSIN_G(coredump) && loglevel == S_MEMORY) {
		volatile unsigned int *x = 0;
		volatile int y = *x;
	}
	
	if (SUHOSIN_G(log_use_x_forwarded_for)) {
		ip_address = suhosin_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC);
		if (ip_address == NULL) {
			ip_address = "X-FORWARDED-FOR not set";
		}
	} else {
		ip_address = suhosin_getenv("REMOTE_ADDR", 11 TSRMLS_CC);
		if (ip_address == NULL) {
			ip_address = "REMOTE_ADDR not set";
		}
	}
	
	
	va_start(ap, fmt);
	ap_php_vsnprintf(error, sizeof(error), fmt, ap);
	va_end(ap);
	while (error[i]) {
		if (error[i] < 32) error[i] = '.';
		i++;
	}
	
	if (SUHOSIN_G(simulation)) {
		alertstring = "ALERT-SIMULATION";
	} else {
		alertstring = "ALERT";
	}
	
	if (zend_is_executing(TSRMLS_C)) {
		zend_execute_data *exdata = EG(current_execute_data);
		if (exdata) {
			if (getcaller && exdata->prev_execute_data) {
				lineno = exdata->prev_execute_data->opline->lineno;
				fname = (char *)exdata->prev_execute_data->op_array->filename;									
			} else {
				lineno = exdata->opline->lineno;
				fname = (char *)exdata->op_array->filename;				
			}
		} else {
			lineno = zend_get_executed_lineno(TSRMLS_C);
			fname = (char *)zend_get_executed_filename(TSRMLS_C);
		}
		ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s', line %u)", alertstring, error, ip_address, fname, lineno);
	} else {
		fname = suhosin_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC);
		if (fname==NULL) {
			fname = "unknown";
		}
		ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s')", alertstring, error, ip_address, fname);
	}
			
	/* Syslog-Logging disabled? */
	if (((SUHOSIN_G(log_syslog)|S_INTERNAL) & loglevel)==0) {
		goto log_file;
	}	
	
#if defined(AF_UNIX)
	ap_php_snprintf(error, sizeof(error), "<%u>suhosin[%u]: %s\n", (unsigned int)(SUHOSIN_G(log_syslog_facility)|SUHOSIN_G(log_syslog_priority)),getpid(),buf);

	s = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (s == -1) {
		goto log_file;
	}
	
	memset(&saun, 0, sizeof(saun));
	saun.sun_family = AF_UNIX;
	strcpy(saun.sun_path, SYSLOG_PATH);
	/*saun.sun_len = sizeof(saun);*/
	
	r = connect(s, (struct sockaddr *)&saun, sizeof(saun));
	if (r) {
		close(s);
    		s = socket(AF_UNIX, SOCK_STREAM, 0);
		if (s == -1) {
			goto log_file;
		}
	
		memset(&saun, 0, sizeof(saun));
		saun.sun_family = AF_UNIX;
		strcpy(saun.sun_path, SYSLOG_PATH);
		/*saun.sun_len = sizeof(saun);*/

		r = connect(s, (struct sockaddr *)&saun, sizeof(saun));
		if (r) { 
			close(s);
			goto log_file;
		}
	}
	send(s, error, strlen(error), 0);
	
	close(s);
#endif
#ifdef PHP_WIN32
	ap_php_snprintf(error, sizeof(error), "suhosin[%u]: %s", getpid(),buf);

	switch (SUHOSIN_G(log_syslog_priority)) {			/* translate UNIX type into NT type */
		case 1: /*LOG_ALERT:*/
			etype = EVENTLOG_ERROR_TYPE;
			break;
		case 6: /*LOG_INFO:*/
			etype = EVENTLOG_INFORMATION_TYPE;
			break;
		default:
			etype = EVENTLOG_WARNING_TYPE;
	}
	evid = loglevel;
	strs[0] = error;
	/* report the event */
	if (log_source == NULL) {
		log_source = RegisterEventSource(NULL, "Suhosin-" SUHOSIN_EXT_VERSION);
	}
	ReportEvent(log_source, etype, (unsigned short) SUHOSIN_G(log_syslog_priority), evid, NULL, 1, 0, strs, NULL);
	
#endif
log_file:
	/* File-Logging disabled? */
	if ((SUHOSIN_G(log_file) & loglevel)==0) {
		goto log_sapi;
	}
	
	if (!SUHOSIN_G(log_filename) || !SUHOSIN_G(log_filename)[0]) {
		goto log_sapi;
	}
	fd = open(SUHOSIN_G(log_filename), O_CREAT|O_APPEND|O_WRONLY, 0640);
	if (fd == -1) {
	    suhosin_log(S_INTERNAL, "Unable to open logfile: %s", SUHOSIN_G(log_filename));
	    return;
	}

	gettimeofday(&tv, NULL);
	now = tv.tv_sec;
	php_gmtime_r(&now, &tm);
	ap_php_snprintf(error, sizeof(error), "%s %2d %02d:%02d:%02d [%u] %s\n", month_names[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, getpid(),buf);
	towrite = strlen(error);
	wbuf = error;
	php_flock(fd, LOCK_EX);
	while (towrite > 0) {
		written = write(fd, wbuf, towrite);
		if (written < 0) {
			break;
		}
		towrite -= written;
		wbuf += written;
	}
	php_flock(fd, LOCK_UN);
	close(fd);

log_sapi:
	/* SAPI Logging activated? */
	SDEBUG("(suhosin_log) log_syslog: %u - log_sapi: %u - log_script: %u - log_phpscript: %u", SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script), SUHOSIN_G(log_phpscript));
	if (((SUHOSIN_G(log_sapi)|S_INTERNAL) & loglevel)!=0) {
#if PHP_VERSION_ID < 50400
		sapi_module.log_message(buf);
#else
		sapi_module.log_message(buf TSRMLS_CC);
#endif
	}
	if ((SUHOSIN_G(log_stdout) & loglevel)!=0) {
		printf("%s\n", buf);
	}

/*log_script:*/
	/* script logging activaed? */
	if (((SUHOSIN_G(log_script) & loglevel)!=0) && SUHOSIN_G(log_scriptname)!=NULL) {
		char cmd[8192], *cmdpos, *bufpos;
		FILE *in;
		int space;
		struct stat st;
		
		char *sname = SUHOSIN_G(log_scriptname);
		while (isspace(*sname)) ++sname;
		if (*sname == 0) goto log_phpscript;
		
		if (VCWD_STAT(sname, &st) < 0) {
			suhosin_log(S_INTERNAL, "unable to find logging shell script %s - file dropped", sname);
			goto log_phpscript;
		}
		if (access(sname, X_OK|R_OK) < 0) {
			suhosin_log(S_INTERNAL, "logging shell script %s is not executable - file dropped", sname);
			goto log_phpscript;					
		}
		
		/* TODO: clean up this code to calculate size of output dynamically */
		ap_php_snprintf(cmd, sizeof(cmd) - 20, "%s %s \'", sname, loglevel2string(loglevel));
		space = sizeof(cmd) - strlen(cmd) - 20;
		cmdpos = cmd + strlen(cmd);
		bufpos = buf;
		if (space <= 1) return;
		while (space > 2 && *bufpos) {
			if (*bufpos == '\'') {
				if (space<=5) break;
				*cmdpos++ = '\'';
				*cmdpos++ = '\\';
				*cmdpos++ = '\'';
				*cmdpos++ = '\'';
				bufpos++;
				space-=4;
			} else {
				*cmdpos++ = *bufpos++;
				space--;
			}
		}
		*cmdpos++ = '\'';
		*cmdpos++ = ' ';
		*cmdpos++ = '2';
		*cmdpos++ = '>';
		*cmdpos++ = '&';
		*cmdpos++ = '1';
		*cmdpos = 0;
		
		if ((in=VCWD_POPEN(cmd, "r"))==NULL) {
			suhosin_log(S_INTERNAL, "Unable to execute logging shell script: %s", sname);
			goto log_phpscript;
		}
		/* read and forget the result */
		while (1) {
			int readbytes = fread(cmd, 1, sizeof(cmd), in);
			if (readbytes<=0) {
				break;
			}
			if (strncmp(cmd, "sh: ", 4) == 0) {
				/* assume this is an error */
				suhosin_log(S_INTERNAL, "Error while executing logging shell script: %s", sname);
				pclose(in);
				goto log_phpscript;
			}
		}
		pclose(in);
	}
log_phpscript:
	if ((SUHOSIN_G(log_phpscript) & loglevel)!=0 && EG(in_execution) && SUHOSIN_G(log_phpscriptname) && SUHOSIN_G(log_phpscriptname)[0]) {
		zend_file_handle file_handle;
		zend_op_array *new_op_array;
		zval *result = NULL;
		
		long orig_execution_depth = SUHOSIN_G(execution_depth);
#if PHP_VERSION_ID < 50400
		zend_bool orig_safe_mode = PG(safe_mode);
#endif
		char *orig_basedir = PG(open_basedir);
		
		char *phpscript = SUHOSIN_G(log_phpscriptname);
SDEBUG("scriptname %s", SUHOSIN_G(log_phpscriptname));				
#ifdef ZEND_ENGINE_2
		if (zend_stream_open(phpscript, &file_handle TSRMLS_CC) == SUCCESS) {
#else
		if (zend_open(phpscript, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) {
			file_handle.filename = phpscript;
			file_handle.free_filename = 0;
#endif		
			if (!file_handle.opened_path) {
				file_handle.opened_path = estrndup(phpscript, strlen(phpscript));
			}
			new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
			zend_destroy_file_handle(&file_handle TSRMLS_CC);
			if (new_op_array) {
				HashTable *active_symbol_table = EG(active_symbol_table);
				zval *zerror, *zerror_class;
				
				if (active_symbol_table == NULL) {
					active_symbol_table = &EG(symbol_table);
				}
				EG(return_value_ptr_ptr) = &result;
				EG(active_op_array) = new_op_array;
				
				MAKE_STD_ZVAL(zerror);
				MAKE_STD_ZVAL(zerror_class);
				ZVAL_STRING(zerror, buf, 1);
				ZVAL_LONG(zerror_class, loglevel);

				zend_hash_update(active_symbol_table, "SUHOSIN_ERROR", sizeof("SUHOSIN_ERROR"), (void **)&zerror, sizeof(zval *), NULL);
				zend_hash_update(active_symbol_table, "SUHOSIN_ERRORCLASS", sizeof("SUHOSIN_ERRORCLASS"), (void **)&zerror_class, sizeof(zval *), NULL);
				
				SUHOSIN_G(execution_depth) = 0;
				if (SUHOSIN_G(log_phpscript_is_safe)) {
#if PHP_VERSION_ID < 50400
					PG(safe_mode) = 0;
#endif
					PG(open_basedir) = NULL;
				}
				
				zend_execute(new_op_array TSRMLS_CC);
				
				SUHOSIN_G(execution_depth) = orig_execution_depth;
#if PHP_VERSION_ID < 50400				
				PG(safe_mode) = orig_safe_mode;
#endif
				PG(open_basedir) = orig_basedir;
				
#ifdef ZEND_ENGINE_2
				destroy_op_array(new_op_array TSRMLS_CC);
#else
				destroy_op_array(new_op_array);
#endif
				efree(new_op_array);
#ifdef ZEND_ENGINE_2
				if (!EG(exception))
#endif			
				{
					if (EG(return_value_ptr_ptr)) {
						zval_ptr_dtor(EG(return_value_ptr_ptr));
						EG(return_value_ptr_ptr) = NULL;
					}
				}
			} else {
				suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname));
				return;
			}
		} else {
			suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname));
			return;
		}
	}

}
Esempio n. 7
0
/* {{{ php_date
 */
static void php_date(INTERNAL_FUNCTION_PARAMETERS, int gm)
{
	pval **format, **timestamp;
	time_t the_time;
	struct tm *ta, tmbuf;
	int i, size = 0, length, h, beat, fd, wd, yd, wk;
	char tmp_buff[32];
#if !HAVE_TM_GMTOFF
	long tzone;
	char *tname[2]= {"GMT Standard Time", "BST"};
#endif

	switch(ZEND_NUM_ARGS()) {
	case 1:
		if (zend_get_parameters_ex(1, &format) == FAILURE) {
			WRONG_PARAM_COUNT;
		}
		the_time = time(NULL);
		break;
	case 2:
		if (zend_get_parameters_ex(2, &format, &timestamp) == FAILURE) {
			WRONG_PARAM_COUNT;
		}
		convert_to_long_ex(timestamp);
		the_time = Z_LVAL_PP(timestamp);
#ifdef PHP_WIN32
		if (the_time < 0) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Windows does not support dates prior to midnight (00:00:00), January 1, 1970");
			RETURN_FALSE;
		}
#endif
		break;
	default:
		WRONG_PARAM_COUNT;
	}
	convert_to_string_ex(format);

	if (gm) {
		ta = php_gmtime_r(&the_time, &tmbuf);
#if !HAVE_TM_GMTOFF
		tzone = 0;
#endif
	} else {
		ta = php_localtime_r(&the_time, &tmbuf);
#if !HAVE_TM_GMTOFF
#ifdef __CYGWIN__
		tzone = _timezone;
#else
		tzone = timezone;
#endif
		if (tzname[0] != NULL) {
			tname[0] = tzname[0];
		} else {
			tname[0] = "???";
		}

		if (tzname[1] != NULL) {
			tname[1] = tzname[1];
		}
#endif
	}

	if (!ta) {			/* that really shouldn't happen... */
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected error");
		RETURN_FALSE;
	}
	for (i = 0; i < Z_STRLEN_PP(format); i++) {
		switch (Z_STRVAL_PP(format)[i]) {
			case 'r':		/* rfc822 format */
				size += 31;
				break;
			case 'U':		/* seconds since the epoch */
				size += 10;
				break;
			case 'F':		/* month, textual, full */
			case 'l':		/* day (of the week), textual */
				size += 28;
				break;
			case 'T':		/* timezone name */
#if HAVE_TM_ZONE
				size += strlen(ta->tm_zone);
#elif HAVE_TZNAME
				if (ta->tm_isdst > 0 ) {
					size += strlen(tname[1]);
				} else {
					size += strlen(tname[0]);
				}
#endif
				break;
			case 'Z':		/* timezone offset in seconds */
				size += 6;
				break;
			case 'O':		/* GMT offset in [+-]HHMM format */
				size += 5;
				break;
			case 'Y':		/* year, numeric, 4 digits */
				size += 4;
				break;
			case 'M':		/* month, textual, 3 letters */
			case 'D':		/* day, textual, 3 letters */
			case 'z':		/* day of the year, 1 to 366 */
			case 'B':		/* Swatch Beat, 3 digits */
				size += 3;
				break;
			case 'y':		/* year, numeric, 2 digits */
			case 'm':		/* month, numeric */
			case 'n':		/* month, numeric, no leading zeroes */
			case 'd':		/* day of the month, numeric */
			case 'j':		/* day of the month, numeric, no leading zeros */
			case 'H':		/* hour, numeric, 24 hour format */
			case 'h':		/* hour, numeric, 12 hour format */
			case 'G':		/* hour, numeric, 24 hour format, no leading zeroes */
			case 'g':		/* hour, numeric, 12 hour format, no leading zeroes */
			case 'i':		/* minutes, numeric */
			case 's':		/* seconds, numeric */
			case 'A':		/* AM/PM */
			case 'a':		/* am/pm */
			case 'S':		/* standard english suffix for the day of the month (e.g. 3rd, 2nd, etc) */
			case 't':		/* days in current month */
			case 'W':		/* ISO-8601 week number of year, weeks starting on Monday */
				size += 2;
				break;
			case '\\':
				if (i < Z_STRLEN_PP(format) - 1) {
					i++;
				}
				size ++;
				break;
			case 'L':		/* boolean for leap year */
			case 'w':		/* day of the week, numeric */
			case 'I':		/* DST? */
			default:
				size++;
				break;
		}
	}

	Z_STRVAL_P(return_value) = (char *) emalloc(size + 1);
	Z_STRVAL_P(return_value)[0] = '\0';

	for (i = 0; i < Z_STRLEN_PP(format); i++) {
		switch (Z_STRVAL_PP(format)[i]) {
			case '\\':
				if (i < Z_STRLEN_PP(format) - 1) {
					char ch[2];
					ch[0]=Z_STRVAL_PP(format)[i + 1];
					ch[1]='\0';
					strcat(Z_STRVAL_P(return_value), ch);
					i++;
				}
				break;
			case 'U':		/* seconds since the epoch */
				sprintf(tmp_buff, "%ld", (long)the_time); /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'F':		/* month, textual, full */
				strcat(Z_STRVAL_P(return_value), mon_full_names[ta->tm_mon]);
				break;
			case 'l':		/* day (of the week), textual, full */
				strcat(Z_STRVAL_P(return_value), day_full_names[ta->tm_wday]);
				break;
			case 'Y':		/* year, numeric, 4 digits */
				sprintf(tmp_buff, "%d", ta->tm_year + YEAR_BASE);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'M':		/* month, textual, 3 letters */
				strcat(Z_STRVAL_P(return_value), mon_short_names[ta->tm_mon]);
				break;
			case 'D':		/* day (of the week), textual, 3 letters */
				strcat(Z_STRVAL_P(return_value), day_short_names[ta->tm_wday]);
				break;
			case 'z':		/* day (of the year) */
				sprintf(tmp_buff, "%d", ta->tm_yday);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'y':		/* year, numeric, 2 digits */
				sprintf(tmp_buff, "%02d", ((ta->tm_year)%100));  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'm':		/* month, numeric */
				sprintf(tmp_buff, "%02d", ta->tm_mon + 1);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'n':      /* month, numeric, no leading zeros */
				sprintf(tmp_buff, "%d", ta->tm_mon + 1);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'd':		/* day of the month, numeric */
				sprintf(tmp_buff, "%02d", ta->tm_mday);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'j':
				sprintf(tmp_buff, "%d", ta->tm_mday); /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'H':		/* hour, numeric, 24 hour format */
				sprintf(tmp_buff, "%02d", ta->tm_hour);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'h':		/* hour, numeric, 12 hour format */
				h = ta->tm_hour % 12; if (h==0) h = 12;
				sprintf(tmp_buff, "%02d", h);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'G':      /* hour, numeric, 24 hour format, no leading zeros */
				sprintf(tmp_buff, "%d", ta->tm_hour);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'g':      /* hour, numeric, 12 hour format, no leading zeros */
				h = ta->tm_hour % 12; if (h==0) h = 12;
				sprintf(tmp_buff, "%d", h);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'i':		/* minutes, numeric */
				sprintf(tmp_buff, "%02d", ta->tm_min);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 's':		/* seconds, numeric */
				sprintf(tmp_buff, "%02d", ta->tm_sec);  /* SAFE */ 
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'A':		/* AM/PM */
				strcat(Z_STRVAL_P(return_value), (ta->tm_hour >= 12 ? "PM" : "AM"));
				break;
			case 'a':		/* am/pm */
				strcat(Z_STRVAL_P(return_value), (ta->tm_hour >= 12 ? "pm" : "am"));
				break;
			case 'S':		/* standard english suffix, e.g. 2nd/3rd for the day of the month */
				if (ta->tm_mday >= 10 && ta->tm_mday <= 19) {
					strcat(Z_STRVAL_P(return_value), "th");
				} else {
					switch (ta->tm_mday % 10) {
						case 1:
							strcat(Z_STRVAL_P(return_value), "st");
							break;
						case 2:
							strcat(Z_STRVAL_P(return_value), "nd");
							break;
						case 3:
							strcat(Z_STRVAL_P(return_value), "rd");
							break;
						default:
							strcat(Z_STRVAL_P(return_value), "th");
							break;
					}
				}
				break;
			case 't':		/* days in current month */
				sprintf(tmp_buff, "%2d", phpday_tab[isleap((ta->tm_year+YEAR_BASE))][ta->tm_mon] );
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'w':		/* day of the week, numeric EXTENSION */
				sprintf(tmp_buff, "%01d", ta->tm_wday);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'O':		/* GMT offset in [+-]HHMM format */
#if HAVE_TM_GMTOFF				
				sprintf(tmp_buff, "%c%02d%02d", (ta->tm_gmtoff < 0) ? '-' : '+', abs(ta->tm_gmtoff / 3600), abs( (ta->tm_gmtoff % 3600) / 60 ));
#else
				sprintf(tmp_buff, "%c%02d%02d", ((ta->tm_isdst ? tzone - 3600:tzone)>0)?'-':'+', abs((ta->tm_isdst ? tzone - 3600 : tzone) / 3600), abs(((ta->tm_isdst ? tzone - 3600 : tzone) % 3600) / 60));
#endif
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'Z':		/* timezone offset in seconds */
#if HAVE_TM_GMTOFF
				sprintf(tmp_buff, "%ld", ta->tm_gmtoff);
#else
				sprintf(tmp_buff, "%ld", ta->tm_isdst ? -(tzone- 3600) : -tzone);
#endif
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'L':		/* boolean for leapyear */
				sprintf(tmp_buff, "%d", (isleap((ta->tm_year+YEAR_BASE)) ? 1 : 0 ) );
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'T':		/* timezone name */
#if HAVE_TM_ZONE
				strcat(Z_STRVAL_P(return_value), ta->tm_zone);
#elif HAVE_TZNAME
				strcat(Z_STRVAL_P(return_value), ta->tm_isdst ? tname[1] : tname[0]);
#endif
				break;
			case 'B':	/* Swatch Beat a.k.a. Internet Time */
				beat =  (((((long)the_time)-(((long)the_time) -
					((((long)the_time) % 86400) + 3600))) * 10) / 864);
				while (beat < 0) {
					beat += 1000;
				}
				beat = beat % 1000;
				sprintf(tmp_buff, "%03d", beat); /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'I':
				sprintf(tmp_buff, "%d", ta->tm_isdst);
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'r':
#if HAVE_TM_GMTOFF
				sprintf(tmp_buff, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
					day_short_names[ta->tm_wday],
					ta->tm_mday,
					mon_short_names[ta->tm_mon],
					ta->tm_year + YEAR_BASE,
					ta->tm_hour,
					ta->tm_min,
					ta->tm_sec,
					(ta->tm_gmtoff < 0) ? '-' : '+',
					abs(ta->tm_gmtoff / 3600),
					abs( (ta->tm_gmtoff % 3600) / 60 )
				);
#else
				sprintf(tmp_buff, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
					day_short_names[ta->tm_wday],
					ta->tm_mday,
					mon_short_names[ta->tm_mon],
					ta->tm_year + YEAR_BASE,
					ta->tm_hour,
					ta->tm_min,
					ta->tm_sec,
					((ta->tm_isdst ? tzone - 3600 : tzone) > 0) ? '-' : '+',
					abs((ta->tm_isdst ? tzone - 3600 : tzone) / 3600),
					abs( ((ta->tm_isdst ? tzone - 3600 : tzone) % 3600) / 60 )
				);
#endif
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;
			case 'W':		/* ISO-8601 week number of year, weeks starting on Monday */
				wd = ta->tm_wday == 0 ? 6 : ta->tm_wday - 1; /* weekday */
				yd = ta->tm_yday + 1;					/* days since January 1st */

				fd = (7 + wd - yd % 7+ 1) % 7;			/* weekday (1st January) */	

				/* week is a last year week (52 or 53) */
				if ((yd <= 7 - fd) && fd > 3){			
					wk = (fd == 4 || (fd == 5 && isleap((ta->tm_year + YEAR_BASE - 1)))) ? 53 : 52;
				}
				/* week is a next year week (1) */
				else if (isleap((ta->tm_year+YEAR_BASE)) + 365 - yd < 3 - wd){
					wk = 1;
				}
				/* normal week */
				else {
					wk = (yd + 6 - wd + fd) / 7 - (fd > 3);
				}

				sprintf(tmp_buff, "%02d", wk);  /* SAFE */
				strcat(Z_STRVAL_P(return_value), tmp_buff);
				break;

			default:
				length = strlen(Z_STRVAL_P(return_value));
				Z_STRVAL_P(return_value)[length] = Z_STRVAL_PP(format)[i];
				Z_STRVAL_P(return_value)[length + 1] = '\0';
				break;
		}
	}
	Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
	Z_TYPE_P(return_value) = IS_STRING;
}