Skip to content

Instantly share code, notes, and snippets.

@yohgaki
Last active October 21, 2016 02:20
Show Gist options
  • Save yohgaki/b86e07cd450777422c1a467166cd2fd3 to your computer and use it in GitHub Desktop.
Save yohgaki/b86e07cd450777422c1a467166cd2fd3 to your computer and use it in GitHub Desktop.
Allow something like setcookie('A', 'B', ['expires'=>time()+999, 'httponly'=>1]);
diff --git a/ext/standard/head.c b/ext/standard/head.c
index eac9159..4842cb7d 100644
--- a/ext/standard/head.c
+++ b/ext/standard/head.c
@@ -181,6 +181,74 @@ PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires,
return result;
}
+enum cookie_set_opts {
+ COOKIE_SET_EXPIRES = 0,
+ COOKIE_SET_PATH,
+ COOKIE_SET_DOMAIN,
+ COOKIE_SET_SECURE,
+ COOKIE_SET_HTTPONLY,
+ COOKIE_SET_INVALID
+};
+
+static int cookie_set_options(zval *options, zend_long *expires, zend_string **path, zend_string **domain, zend_bool *secure, zend_bool *httponly) { /* {{{ */
+ zend_long idx;
+ zend_string *key;
+ zval *el;
+ char *allowed_opts[] = {"expires","path","domain","secure","httponly"};
+ int opt, i;
+
+ (void)(idx);
+
+ ZEND_ASSERT(Z_TYPE_P(options) == IS_ARRAY);
+ ZEND_HASH_FOREACH_KEY_VAL(HASH_OF(options), idx, key, el) {
+ if (!key) {
+ php_error_docref(NULL, E_WARNING, "Options array should not have numeric key");
+ return FAILURE;
+ }
+ opt = COOKIE_SET_INVALID;
+ for (i = 0; i < COOKIE_SET_INVALID; i++) {
+ if (!strncasecmp(allowed_opts[i], ZSTR_VAL(key), ZSTR_LEN(key))) {
+ opt = i;
+ break;
+ }
+ }
+ switch(opt) {
+ case COOKIE_SET_EXPIRES:
+ convert_to_long(el);
+ *expires = Z_LVAL_P(el);
+ continue;
+ case COOKIE_SET_PATH:
+ convert_to_string(el);
+ *path = zend_string_init(Z_STRVAL_P(el),Z_STRLEN_P(el), 0);
+ continue;
+ case COOKIE_SET_DOMAIN:
+ convert_to_string(el);
+ *domain = zend_string_init(Z_STRVAL_P(el),Z_STRLEN_P(el), 0);
+ continue;
+ case COOKIE_SET_SECURE:
+ convert_to_boolean(el);
+ *secure = Z_LVAL_P(el);
+ continue;
+ case COOKIE_SET_HTTPONLY:
+ convert_to_boolean(el);
+ *httponly = Z_LVAL_P(el);
+ continue;
+ default:
+ if (*domain) {
+ zend_string_release(*domain);
+ }
+ if (*path) {
+ zend_string_release(*path);
+ }
+ php_error_docref(NULL, E_WARNING, "Invalid opton (%s)", ZSTR_VAL(key));
+ return FAILURE;
+ }
+ }
+ ZEND_HASH_FOREACH_END();
+
+ return SUCCESS;
+}
+/* }}} */
/* php_set_cookie(name, value, expires, path, domain, secure) */
/* {{{ proto bool setcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly]]]]]])
@@ -188,19 +256,54 @@ PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires,
PHP_FUNCTION(setcookie)
{
zend_string *name, *value = NULL, *path = NULL, *domain = NULL;
+ zend_string *path_tmp = NULL, *domain_tmp = NULL;
+ zval *options;
zend_long expires = 0;
zend_bool secure = 0, httponly = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|SlSSbb",
- &name, &value, &expires, &path, &domain, &secure, &httponly) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|SzSSbb",
+ &name, &value, &options, &path, &domain, &secure, &httponly) == FAILURE) {
return;
}
+ switch (Z_TYPE_P(options)) {
+ case IS_UNDEF:
+ /* nothing to do */
+ break;
+ case IS_ARRAY:
+ if (cookie_set_options(options, &expires, &path_tmp, &domain_tmp, &secure, &httponly) == FAILURE) {
+ RETURN_FALSE;
+ }
+ path = path_tmp;
+ domain = domain_tmp;
+ break;
+ case IS_NULL:
+ case IS_TRUE:
+ case IS_FALSE:
+ case IS_STRING:
+ case IS_DOUBLE:
+ convert_to_long(options);
+ expires = Z_LVAL_P(options);
+ break;
+ case IS_LONG:
+ expires = Z_LVAL_P(options);
+ break;
+ default:
+ php_error_docref(NULL, E_WARNING, "3rd parameter must be array or long");
+ RETURN_FALSE;
+ }
+
if (php_setcookie(name, value, expires, path, domain, secure, 1, httponly) == SUCCESS) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
+ if (path_tmp) {
+ zend_string_release(path_tmp);
+ }
+ if (domain_tmp) {
+ zend_string_release(domain_tmp);
+ }
}
/* }}} */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment