числовые типы данных PHP и Mysql

Духовность™

Продвинутый новичок
числовые типы данных PHP и Mysql

Поскольку в PHP и Mysql на 32 системах можно работать с разными типами данных, меня смутили некоторые вещи. Ну, например есть у нас в базе ID = 18446744073709551615 (это bigint, unsigned)
и мы хотим сделать SQL запрос на выборку. ID пришел из REQUEST и мы хотим его "обеззаразить". Как это сделать "чистыми" средствами PHP? Я добился этого только с помощью расширения filter. Это нормально или я туплю?

PHP:
<?php
error_reporting (E_ALL);

$request_id = '18446744073709551615какашки';
var_dump($request_id);

$int = intval($request_id);
var_dump($int); // int 2147483647

echo '<br>';

$new = 0 + $request_id;
var_dump($new); // float 1.84467440737E+19

echo '<br>';

$filter = filter_var($request_id, FILTER_SANITIZE_NUMBER_INT);
var_dump($filter); // string '18446744073709551615'
?>
 

lart

Guest
можно просто регапсами preg_replace('/\D/','',$request_id) ;

P.S. Это если не нужно проверять насколько число большое
 

Духовность™

Продвинутый новичок
Не, регэкспы это тоже расширение языка. Меня интересует две вещи.

1. Как это делать на уровне ядра.

2. Нужно ли вообще в PHP к числовым идентификаторам из других приложений (из базы, например) относиться как к переменным числового типа? Или же с ними надо ВСЕГДА работать как со строками?
 

fixxxer

К.О.
Партнер клуба
меня это все настолько достало что я с некоторых пор просто требую, чтобы ОС была 64 битной. :) хотя с bigint и это не поможет.

а по сути вопроса - проще со строками, да. через filter нормальное решение, если его не стоит - регуляркой.
 

Духовность™

Продвинутый новичок
а по сути вопроса - проще со строками, да.
ну я так и понял.

Просто я щас начал разгребать, что писал раньше и наткнулся на свой жесточайший баг, вызванный непониманием того, что int в PHP это не больше 2147483647. У меня были утрированно такие коды:

PHP:
query('select * from table where id = '.intval($_REQUEST['id']))
для таблиц, где PK int unsigned и более :cool:

т.е. я программно занижал все числовые ID больше чем max int. :D
 

fixxxer

К.О.
Партнер клуба
у меня такое же есть :D

причем я в курсе, просто до таких идов еще долго :D

впрочем исправляется это все в одном единственном месте в либе при необходимости.
 

Breeze

goshogun
Команда форума
Партнер клуба
Автор оригинала: triumvirat
Не, регэкспы это тоже расширение языка. Меня интересует две вещи.

1. Как это делать на уровне ядра.

2. Нужно ли вообще в PHP к числовым идентификаторам из других приложений (из базы, например) относиться как к переменным числового типа? Или же с ними надо ВСЕГДА работать как со строками?
на уровне ядра никак, у php int по-умолчанию signed, можно только в unsigned преобразовать, все остальное, проходящее проверку is_numeric , воспринимается как строка, соответственно с этим и надо как со строками работать.

зачем вообще тебе сдался unsigned bigint? 4-х миллиардов unsigned int мало?
 

Духовность™

Продвинутый новичок
можно только в unsigned преобразовать
ты про что?

зачем вообще тебе сдался unsigned bigint? 4-х миллиардов unsigned int мало?
мне он не сдался, просто я на баг наткнулся, когда в запросе было число большее чем PHP_INT_MAX, и из-за приведения его к типу int тупо сокращало свое значение. Вот я и задумался.
 

Breeze

goshogun
Команда форума
Партнер клуба
Автор оригинала: triumvirat
ты про что?


мне он не сдался, просто я на баг наткнулся, когда в запросе было число большее чем PHP_INT_MAX, и из-за приведения его к типу int тупо сокращало свое значение. Вот я и задумался.
я про sprintf, т.е. число от -2147483648 до +2147483647 можно преобразовать от 0 до ULONG_MAX. Это он умеет.
а в остальном жопа, даже с int'ом.

Я вот недавно поимел баг со сборкой и спрашивал про результат кода, а там весело было. Число больше 2147483647, но меньше-равно ULONG_MAX приводилось к соответствующему отрицательному значению signed int, а не к строковому.
Вместо string "2147483648" было int -1 и т.д.

Т.е. внутри php все про них знает, но виду не показывает.
 

korpus

злой бобёр
triumvirat, попробуй преобразовать такую переменную
Код:
$request_id = '1844674407370955161+5какашки';
Плюс останется и будет висеть в получившейся строке с числом. Фильтры не годятся. С регулярными выражения получается результат предсказуемее.
Код:
<?php 
error_reporting (E_ALL); 

$request_id = "1844674407370955\r\n1615какашки+промакашки"; 
var_dump($request_id); 

echo '<br>'; 

$new_id=preg_split("/\D/s", $request_id, 2, PREG_SPLIT_NO_EMPTY);
$new_id2=$new_id[0];
var_dump($new_id2); // string(16) "1844674407370955"
?>
По правде сказать, решение располагается в две строчки, что не очень аккуратно. Сам бился над задачей больших целых чисел в php и вот благодаря этой теме что-то полезное для себя смог извлечь.
 

dimagolov

Новичок
у меня есть такой код:
PHP:
/**
* is_bigint
*
* Test if the vaule is valid for MySQL bigint field
* Return TRUE for numeric non-float values (integer or string) and NULL
* Return FALSE for empty or spaced strings, boolean values (even TRUE)
* Ignore begining or ending spaces or NL
* !!! Does not check length of the value, so overflow is possible
*
* @param mixed $Value value to test
*
* @return boolean: result of test
*
*/
function is_bigint($Value) {
	if ($Value === TRUE) return FALSE;
	if ($Value === NULL) return TRUE;
	$Value= trim($Value, " \t\n\r");
	$trimmed= trim($Value, '+-0123456789');
	return (is_numeric($Value) && empty($trimmed));
}

/**
* is_nonempty_bigint
*
* Test if the vaule pass is_bigint and non-zero or non-null
*
* @param mixed $Value value to test
*
* @return boolean: result of test
*
*/
function is_nonempty_bigint($Value) {
	return (!!$Value && intval($Value) && is_bigint($Value));
}
cмысл в том, что проверенные таким образом числа можно вставлять в запросы без экранирования.
 

korpus

злой бобёр
Это же просто проверка.
Надо преобразовать число, и если оно преобразовано правильно, то и проверка не нужна. Возьми и используй моё решение :)

-~{}~ 13.08.10 19:23:

P.S. Может кто знает, как его можно в одну строку записать?
 

dimagolov

Новичок
Надо преобразовать число
кому надо? я получаю из MySQL/от клиента строки и вставляю их в запросы как строки. Тем более, что такие большие значения актуальны обычно только для ID и никакие их преобразования не требуются, а только вставка в запрос.
 

fixxxer

К.О.
Партнер клуба
>>Надо преобразовать число,

PHP:
-function is_bigint($Value) { 
+function to_bigint($Value) { 
-    if ($Value === TRUE) return FALSE; 
-    if ($Value === NULL) return TRUE; 
    $Value= trim($Value, " \t\n\r"); 
    $trimmed= trim($Value, '+-0123456789'); 
-    return (is_numeric($Value) && empty($trimmed));
+    return (is_numeric($Value) && empty($trimmed)) ? $Value : null;
}
:D
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
значение '18446744073709551615какашки', очевидно, некорректно
я возвращаю ошибку валидации формы или редирект на дефолтную страницу
imho угадывать, обрезать, обеззараживать не стоит
а где стоит - надо рассматривать по факту


>расширение filter
стоит по дефолту и я везде юзаю его

-~{}~ 13.08.10 22:27:

>1. Как это делать на уровне ядра.
пишешь для embedded-системы с 512кб RAM ?

-~{}~ 13.08.10 22:47:

приму участие в изобретениях велосипеда :)
PHP:
function is_positive_int($value){ //нас же интересует unsigned?
    $value= trim($value, " \t\n\r+");
    return (strlen($value)===strspn($val,'1234567890'));
}
 

Breeze

goshogun
Команда форума
Партнер клуба
Предложу уж и свои треугольненькие колеса:
PHP:
/**
* По аналогии с intval
*/
function longval($intvar='') {
	$intvar = preg_replace("/^(-\d{1,}|\d{0,})([\w\W]+)?$/","\\1",$intvar);
	return !empty($intvar) ? $intvar : '0';
}

$var = longval("18446744073709551615какашки");
var_dump($var);
string(20) "18446744073709551615"
 

zerkms

TDD infected
Команда форума
triumvirat
для проверки данных, пришедших от клиента - более чем хорошая.
 
Сверху