@@ -1299,14 +1299,43 @@ int redis_blocking_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1299
1299
* have specific processing (argument validation, etc) that make them unique
1300
1300
*/
1301
1301
1302
+ /* Attempt to pull a long expiry from a zval. We're more restrictave than zval_get_long
1303
+ * because that function will return integers from things like open file descriptors
1304
+ * which should simply fail as a TTL */
1305
+ static int redis_try_get_expiry (zval * zv , zend_long * lval ) {
1306
+ double dval ;
1307
+
1308
+ /* Success on an actual long or double */
1309
+ if (Z_TYPE_P (zv ) == IS_LONG || Z_TYPE_P (zv ) == IS_DOUBLE ) {
1310
+ * lval = zval_get_long (zv );
1311
+ return SUCCESS ;
1312
+ }
1313
+
1314
+ /* Automatically fail if we're not a string */
1315
+ if (Z_TYPE_P (zv ) != IS_STRING )
1316
+ return FAILURE ;
1317
+
1318
+ /* Attempt to get a long from the string */
1319
+ switch (is_numeric_string (Z_STRVAL_P (zv ), Z_STRLEN_P (zv ), lval , & dval , 0 )) {
1320
+ case IS_DOUBLE :
1321
+ * lval = dval ;
1322
+ /* fallthrough */
1323
+ case IS_LONG :
1324
+ return SUCCESS ;
1325
+ default :
1326
+ return FAILURE ;
1327
+ }
1328
+ }
1329
+
1302
1330
/* SET */
1303
1331
int redis_set_cmd (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1304
1332
char * * cmd , int * cmd_len , short * slot , void * * ctx )
1305
1333
{
1306
1334
smart_string cmdstr = {0 };
1307
1335
zval * z_value , * z_opts = NULL ;
1308
1336
char * key = NULL , * exp_type = NULL , * set_type = NULL ;
1309
- long expire = -1 , exp_set = 0 , keep_ttl = 0 ;
1337
+ long exp_set = 0 , keep_ttl = 0 ;
1338
+ zend_long expire = -1 ;
1310
1339
size_t key_len ;
1311
1340
1312
1341
// Make sure the function is being called correctly
@@ -1316,14 +1345,6 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1316
1345
return FAILURE ;
1317
1346
}
1318
1347
1319
- /* Our optional argument can either be a long (to support legacy SETEX */
1320
- /* redirection), or an array with Redis >= 2.6.12 set options */
1321
- if (z_opts && Z_TYPE_P (z_opts ) != IS_LONG && Z_TYPE_P (z_opts ) != IS_ARRAY
1322
- && Z_TYPE_P (z_opts ) != IS_NULL )
1323
- {
1324
- return FAILURE ;
1325
- }
1326
-
1327
1348
// Check for an options array
1328
1349
if (z_opts && Z_TYPE_P (z_opts ) == IS_ARRAY ) {
1329
1350
HashTable * kt = Z_ARRVAL_P (z_opts );
@@ -1355,8 +1376,12 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1355
1376
set_type = Z_STRVAL_P (v );
1356
1377
}
1357
1378
} ZEND_HASH_FOREACH_END ();
1358
- } else if (z_opts && Z_TYPE_P (z_opts ) == IS_LONG ) {
1359
- expire = Z_LVAL_P (z_opts );
1379
+ } else if (z_opts && Z_TYPE_P (z_opts ) != IS_NULL ) {
1380
+ if (redis_try_get_expiry (z_opts , & expire ) == FAILURE ) {
1381
+ php_error_docref (NULL , E_WARNING , "Expire must be a long, double, or a numeric string" );
1382
+ return FAILURE ;
1383
+ }
1384
+
1360
1385
exp_set = 1 ;
1361
1386
}
1362
1387
@@ -1386,7 +1411,7 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1386
1411
1387
1412
if (exp_type ) {
1388
1413
redis_cmd_append_sstr (& cmdstr , exp_type , strlen (exp_type ));
1389
- redis_cmd_append_sstr_long (& cmdstr , expire );
1414
+ redis_cmd_append_sstr_long (& cmdstr , ( long ) expire );
1390
1415
}
1391
1416
1392
1417
if (set_type )
0 commit comments