PHP pg_query_params

(PHP 5 = 5.1.0, PHP 7)

pg_query_params — Надсилає на запит на сервер, параметри передаються окремо від тексту SQL запиту

Посилає параметризований запит на сервер і чекає на результат. Параметри надсилаються окремо від рядка запиту.

pg_query_params() подібна до функції pg_query() , але надає додатковий функціонал: параметри запиту можна передавати окремо від рядка запиту.pg_query_params() підтримується на з'єднаннях із серверами PostgreSQL версій 7.4 та вище. Функція не працюватиме із серверами ранніх версій.

Якщо використовуються параметри params, вони замінюють псевдозмінні $1, $2 і т.д. у рядку запиту query. Один і той же параметр може бути вказаний більше одного разу на query; у цьому випадку будуть використані однакові значення. params визначають поточні параметри. ЗначенняNULL у масиві параметрів означатиме SQL NULL у запиті.

Головна перевага pg_query_params() перед pg_query() полягає в тому, що значення параметрів можуть передаватися окремо від рядка запиту query . Це дає можливість уникнути стомлюючу і схильну до помилок процедуру екранування спецсимволів і укладання значень у лапки. Однак, на відміну від pg_query() , ця функція підтримує тільки один SQL запит у рядку, що передається. (Він може містити крапку з комою, але не більше однієї непустої SQL-команди.)

Список параметрів

Ресурс підключення до бази даних PostgreSQL. Якщо параметр connection не заданий, буде використано стандартне з'єднання - останнє з'єднання, відкрите функцією pg_connect() або pg_pconnect() .

Параметризований запит SQL. Повинен містити лише один вираз (кілька виразіврозділених крапкою з комою не підтримуються). Якщо в запит будуть передаватися параметри, вони замінять псевдозмінні $1, $2 і т.д.

Користувацькі дані завжди повинні передаватися як параметри, і не передаватися в рядок запиту безпосередньо, де вони можуть призвести до можливих атак через SQL-ін'єкції та призводить до помилок, якщо дані містять лапки. Якщо з якихось причин ви не можете використовувати параметр, переконайтеся, що дані користувача правильно екрановані.

Масив значень параметрів запиту для заміни псевдозмінних $1, $2 і т.д. у вихідному рядку запиту. Кількість елементів масиву має точно збігатися з кількістю псевдозмінних.

Значення призначені для bytea полів не можна передавати в параметрах. Використовуйте pg_escape_bytea() або функції для великих об'єктів.

Значення, що повертаються

Ресурс результату запиту абоFALSE у разі виникнення помилки.

Приклад #1 Приклад використанняpg_query_params()

// Підключення до бази " mary " $dbconn = pg_connect ( "dbname=mary" );

// Знайдемо всі магазини під назвою "Joe's Widgets". Варто зазначити, що немає необхідності екранувати // спецсимволи в рядку "Joe's Widgets" $result = pg_query_params ( $dbconn , 'SELECT * FROM shops WHERE name = $1' , array( "Joe's Widgets" ));

// Для порівняння те саме, використовуючи функцію pg_query $str = pg_escape_string ( "Joe's Widgets" ); $result = pg_query ( $dbconn , "SELECT * FROM shops WHERE name = '< $str >'");

Дивіться також

User Contributed Notes 15 notes

Якщо ви потрібні, щоб забезпечити величезні можливі значення для поля в Select Query, то натисніть, щоб допомогти.

// Assume that $values[] is anмасив, що містить значення, які вас цікавлять. $values ​​= array( 1 , 4 , 5 , 8 );

// Щоб вибрати змінну кількість аргументів за допомогою pg_query(), ви можете використати: $valuelist = implode ( ', ' , $values ​​); $query = "SELECT * FROM table1 WHERE col1 IN ( $valuelist )" ; $result = pg_query ( $query ) or die( pg_last_error ());

// Замість цього ви повинні використовувати такий підхід: $valuelist = '' $query = 'SELECT * FROM table1 WHERE col1 = ANY ($1)' ; $result = pg_query_params ($query, array($valuelist)); ?> Помилка в цьому прикладі породжується PostGreSQL.

Останній метод працює шляхом створення масиву SQL, що містить потрібні значення. 'IN (. )' і ' = ANY (. )' еквівалентні, але ANY призначений для роботи з масивами, а IN для роботи з простими списками.

Ви не можете запустити кілька операторів за допомогою pg_query_params, але ви все ще можете мати підтримку транзакцій без повернення до pg_query:

= pg_connect ( "host=127.0.0.1 port=5432 dbname=foo user=bar password=baz"); pg_query ( $connection , 'ВИДАЛИТИ ТАБЛИЦЮ, ЯКЩО ІСНУЄ приклад' ); pg_query ( $connection , 'приклад CREATE TABLE (col char(1))'); pg_query ( $connection , 'INSERT INTO example (col) VALUES (\'a\')' ); // 'SELECT col FROM example' в іншому сеансі повертає "a" pg_query ( $connection , 'BEGIN' ); pg_query_params ( $connection , 'ОНОВЛЕННЯ прикладу SET col = $1' , array( 'b' )); // 'SELECT col FROM example' в іншому сеансі все ще повертає "a" pg_query_params ( $connection , 'UPDATE example SET col = $1' , array( 'c' )); // 'SELECT col FROM example' в іншій сесії все ще повертає "a" pg_query ( $connection , 'COMMIT' ); // 'SELECT col FROM example' в іншому сеансі повертає "c" ?>

pg_query іpg_query_params можна об’єднати в одну функцію. Це також усуває необхідність створювати масив параметрів для pg_query_params:

функція my_query ( $conn , $query ) < if( func_num_args () == 2 ) повернути pg_query ( $conn , $query );

$args = func_get_args (); $params = array_splice ($args, 2); повернути pg_query_params ( $conn , $query , $params ); > ?> Використання:

/* непараметризований приклад */ my_query ( $conn , "SELECT $val1 + $val2 " );

/* параметризований приклад */ my_query ( $conn , "SELECT $1 + $2" , $val1 , $val2 ); ?>

= ". "; $params = масив (1, 2, 3, true, false);

//Тепер виконайте запит: $result = pg_query_params ( $sql , $params ); $row = pg_fetch_assoc ( $result , 0 ) //перший рядок

//Для логічних значень, перетворити 't' і 'f' назад на true і false. Перевірте тип стовпця, щоб ми випадково не перетворили неправильну річ. foreach ( $row as $key => & $value ) < $type = pg_field_type ( $result , pg_field_num ( $result , $key )); if ( $type == 'bool' ) $value = ( $value == 't' ); > >

//$row[] тепер містить логічні значення, значення NULL і рядки. ?>

Щодо логічних значень, просто приведіть їх як (ціле число) під час передавання у вашому запиті — «0» і «1» є цілком прийнятними літералами для логічного введення SQL:

Також безпечно писати ваш параметризований запит у подвійних лапках, що дозволяє змішувати постійні значення та заповнювачі у вашому запиті, не турбуючись про те, чи намагатиметься PHP замінити будь-які змінні у вашому параметризованому рядку.

Звичайно, це також означає, що на відміну від синтаксису рядків у подвійних лапках PHP, ви МОЖЕТЕ включити літерали $1, $2 тощо в рядки SQL, наприклад:

//Працює ($1 є заповнювачем, $2 означає буквально) pg_query_params ( "INSERT INTO foo (col1, col2) VALUES ($1, 'costs $2')" , Array( $data1 ));

// Викидає E_WARNING (передаючи забагато параметрів) pg_query_params ( "INSERT INTO foo (col1, col2) VALUES ($1, 'costs $2')" , Array( $data1 , $data2 )); ?>

Вставляючи в стовпець pg типу bool, ви не можете вказати тип bool PHP. Замість цього потрібно використовувати рядок "t" або "f". PHP намагається змінити логічні значення, надані як параметри, на рядки, а потім намагається використовувати порожній рядок для false.

Приклад помилки: pg_query_params('вставити в таблицю1 (bool_column) значення ($1)', array(false));

Працює: pg_query_params('вставити в значення lookup_permissions (система) ($1)', array(false ? 't' : 'f'));

Якщо ваша системна локаль використовує "," як десятковий роздільник, наступне призведе до помилки бази даних:

pg_query_params($conn, 'SELECT $1::numeric', array(3.5));

Щоб це працювало, необхідно вручну перетворити 3.5 на рядок, використовуючи, наприклад, формат_числа.

(Я подав це як помилку №46408, але, очевидно, це очікувана поведінка.)

Якщо ви намагаєтеся відтворити функцію pg_query_params, ви також можете підтримувати значення NULL. Хоча is_int повертає true для значення NULL, форматування для SQL.

function pg_query_params( $db, $query, $parameters ) // Ескейп-параметри за потреби & параметри побудови для функції зворотного виклику глобальні $pg_query_params__parameters; foreach( $parameters as $k=>$v ) if ( is_null($v) ) $parameters[$k] = 'NULL'; > else $parameters[$k] = ( is_int( $v ) ? $v : "'".pg_escape_string( $v)."'" ); > > $pg_query_params__parameters = $parameters;

// Виклик за допомогою pg_query returnpg_query( $db, preg_replace_callback( '/\$([0-9]+)/', 'pg_query_params__callback', $query)); >

Це корисна функція для запобігання атакам SQL-ін’єкцій, тому для тих із нас, хто ще не може оновитися до PHP5.1, ось функція заміни, яка аналогічно працює на старіших версіях PHP.

# Реалізація параметризованих запитів для Postgresql і старіших версій PHP

if( ! function_exists ( 'pg_query_params' ) )

функція pg_query_params__callback ( $at ) глобальні $pg_query_params__parameters ; повернути $pg_query_params__parameters [ $at [ 1 ]- 1 ]; >

функція pg_query_params ( $db , $query , $parameters )

// Параметри екранування за потреби & параметри побудови для функції зворотного виклику глобальні $pg_query_params__parameters ; foreach( $parameters as $k => $v ) $parameters [ $k ] = ( is_int ( $v ) ? $v : "'". pg_escape_string ( $v). "'" ) ; $pg_query_params__parameters = $parameters ;

// Виклик за допомогою pg_query повернути pg_query ( $db , preg_replace_callback ( '/\$([0-9]+)/' , 'pg_query_params__callback' , $query ) );

// Приклад: pg_query_params( $db_resource, "SELECT * FROM table WHERE col1=$1 AND col2=$2", array( 42, "It's ok" ) ); ?>

Якщо один із параметрів є масивом (наприклад, масив int, що передається до збереженої процедури), він має бути позначений як набір у масиві, а не як нотація масиву php.

наприклад: var_dump виводить 2 parms ціле число та масив int aaa: Array ( [0] => 1 [1] => )

Ви не хочете:

Налагодження параметризованих запитів може бути виснажливим, якщо ви хочете вставити запит безпосередньо в PSQL. Ось трюк, який допомагає:

= "ВИБРАТИ * з таблиці WHERE col_a = $1 і col_b=$2 і col_c=$3" ; $params = масив (42 , "рядок" , NULL );

$debug = preg_replace_callback ( '/\$(\d+)\b/' , function( $match ) use ( $params ) < $key =( $match [ 1 ]- 1 ); return ( is_null ( $params [ $key ])? 'NULL' : pg_escape_literal ( $params [ $key ]) ); >, $sql );

echo "$debug" ; //друк: SELECT * із таблиці WHERE col_a = '42' і col_b='рядок' і col_c=NULL ?> Це працює правильно, за винятком (незвичайного) випадку, коли ми маємо літерал $N; регулярний вираз замінює його там, де він не повинен. Наприклад: //Обидва ' . $1 . ' і $1 замінюються; перший неправий, другий правий. $sql = "ВИБЕРІТЬ 'Ваш рахунок на $1' ЯК рахунок-фактура WHERE 7 = $1" ; $params = масив (7); //$debug: ВИБЕРІТЬ 'Ваш рахунок становить 7 доларів США' ЯК рахунок-фактура WHERE 7 = '7'" ?>

pg_query_params() *не* приймає NULL. Вони будуть автоматично перетворені правильно в SQL NULL. Таким чином, наприклад:

= "ОНОВИТИ tbl_example SET column_a = $1, column_b=$2" ; $params = масив (NULL, 42); $result = pg_params ( $sql , $params );

//еквівалентно: $result = pg_query ( "UPDATE tbl_example SET column_a = NULL column_b = '42')" ;

//а не, як можна побоюватися, одну з цих (неправильних) речей: // . стовпець_a = '' . // . column_a = 'NULL' . ?> Зауважте, що таким чином ви можете використовувати NULL у операторах UPDATE або INSERT, але НЕ в реченні WHERE. Це не обмеження pg_query_params(), а скоріше це наслідок мови SQL. Отже, якщо вам потрібен запит типу:

= "ВИБРАТИ. ДЕ Стовпець НЕ ВІДМІНЯЄТЬСЯ ВІД $1" $params = масив ( 42 ); //це працює, так само, як "where column = 42" $params = array ( NULL ); //це працює, так само, як "де стовпець нульовий" ?> (Окремо: хоча це дратує,поведінка правильна. Існує параметр сумісності з postgresql "transform_null_equals", але тут він вам не допоможе, навіть якщо ви цього очікували.)

На жаль, параметри не поважатимуть рядкові представлення NULL або NOW(). Якщо ваш код надсилає ці значення, вони розглядаються як рядок і вставляються буквально як "NULL" і "NOW()".

В ідеалі має бути додатковий параметр, який ви можете призначити, щоб примусово використовувати цей текст як функції pgSQL/зарезервовані слова, а не загортати їх у рядки (припускаючи, що параметризовані запити pgSQL це підтримують.

Ця ж проблема також виникає для списків ком, які використовуються в "WHERE column IN (1,2,3,4)", параметри розглядають "1,2,3,4" як рядок, а не список чисел, і запускають його з також цитати.

Для налагодження я використовую цю функцію для імітації параметрів, пам’ятайте, що це не є 100% точним, вона лише намагається імітувати фактичний SQL, який створюють запити параметрів.

функція pg_query_params_return_sql ( $query , $array ) < $query_parsed = $query ;

for ( $a = 0 , $b = sizeof ( $array ); $a $b ; $a ++) < if ( is_numeric ( $array [ $a ]) ) < $query_parsed = str_replace (( '$' .( $a + 1 )), str_replace ( "'", "''" , $array [ $a ]), $query_parsed ); > інакше < $query_parsed = str_replace (( '$' .( $a + 1 )), "'" . str_replace ( "'" , "''" , $array [ $a ]). "'", $query_parsed ); > >