Pg escape identifier: примеры (PHP)

Экранирование идентификаторов в PostgreSQL через PHP
Раздел: Базы данных (PostgreSQL)
pg_escape_identifier(PgSql\Connection $connection, string $data): string
Функция pg_escape_identifier в PHP

Функция pg_escape_identifier применяется для экранирования идентификаторов (имен таблиц, столбцов, схем) в запросах к PostgreSQL. Её основная задача - предотвращение SQL-инъекций и корректная обработка идентификаторов, содержащих специальные символы или зарезервированные слова.

Использование актуально при динамическом формировании SQL-запросов, где имена объектов базы данных зависят от пользовательского ввода или внешних данных.

Аргументы функции:

  • $connection (ресурс соединения, необязательный с PHP 8.1) - идентификатор подключения к PostgreSQL. Если не указан, используется последнее соединение.
  • $data (string) - строка с идентификатором, который требуется экранировать.

Возвращаемое значение: экранированная строка или false при ошибке.

Примеры использования
Базовое экранирование
<?
$conn = pg_connect('dbname=test');
$table = 'user table';
$escaped = pg_escape_identifier($conn, $table);
echo 'SELECT * FROM ' . $escaped . ';';
?>
SELECT * FROM "user table";
Использование без указания соединения (PHP 8.1+)
<?
$conn = pg_connect('dbname=test');
$column = 'group';
$escaped = pg_escape_identifier($column);
echo 'SELECT ' . $escaped . ' FROM users;';
?>
SELECT "group" FROM users;
Экранирование зарезервированных слов
<?
$conn = pg_connect('dbname=test');
echo pg_escape_identifier($conn, 'order');
?>
"order"
Альтернативные функции в PHP
  • pg_escape_literal - экранирует значения для SQL-запросов, добавляя кавычки. Используется для скалярных значений, а не идентификаторов.
  • pg_escape_string - экранирует спецсимволы в строках, но не добавляет кавычки. Менее безопасна для идентификаторов, чем pg_escape_identifier.
  • Подготовленные выражения (pg_query_params) - наиболее безопасный способ работы с данными, но не поддерживают динамические идентификаторы.

Предпочтительнее использовать pg_escape_identifier именно для имен таблиц и столбцов, а подготовленные выражения - для значений.

Аналоги в других языках
Python (psycopg2)
from psycopg2 import sql
ident = sql.Identifier('user table')
query = sql.SQL('SELECT * FROM {}').format(ident)
print(query.as_string(conn))
SELECT * FROM "user table"
JavaScript (node-postgres)
const { Client } = require('pg');
const client = new Client();
async function escapeExample() {
  const ident = 'user table';
  const query = `SELECT * FROM "${ident}"`;
  // Ручное экранирование
  const escaped = ident.replace(/\"/g, '\"\"');
  console.log(`SELECT * FROM "${escaped}"`);
}
SELECT * FROM "user table"

Pg escape identifier в MySQL

SET @table = 'user table';
SET @query = CONCAT('SELECT * FROM `', REPLACE(@table, '`', '``'), '`');
SELECT @query;
SELECT * FROM `user table`
Типичные ошибки
Отсутствие кавычек в запросе
<?
$conn = pg_connect('dbname=test');
$table = pg_escape_identifier($conn, 'my table');
// Ошибка: пропущены кавычки вокруг идентификатора
$query = 'SELECT * FROM ' . $table;
echo $query;
?>
SELECT * FROM "my table"

Функция не добавляет кавычки автоматически - их нужно включать в запрос.

Использование для значений
<?
$conn = pg_connect('dbname=test');
$value = pg_escape_identifier($conn, "O'Reilly");
$query = 'SELECT * FROM users WHERE name = ' . $value;
echo $query;
?>
SELECT * FROM users WHERE name = "O'Reilly"

Для значений следует использовать pg_escape_literal или подготовленные выражения.

Изменения в версиях PHP
  • PHP 8.1 - параметр $connection стал необязательным. При его отсутствии используется последнее установленное соединение.
  • PHP 8.0 - улучшена обработка ошибок, функция теперь более строго типизирована.
  • PHP 7.0 - добавлена поддержка специальных символов Unicode в идентификаторах.
Расширенные примеры
Динамическое построение запроса с несколькими идентификаторами
Пример php
<?
$conn = pg_connect('dbname=test');
$table = 'user orders';
$columns = ['id', 'order date', 'amount'];
$escapedCols = array_map(fn($col) => pg_escape_identifier($conn, $col), $columns);
$query = 'SELECT ' . implode(', ', $escapedCols) . 
         ' FROM ' . pg_escape_identifier($conn, $table) . 
         ' WHERE ' . pg_escape_identifier($conn, 'order date') . ' > NOW() - INTERVAL \'7 days\'';
echo $query;
?>
SELECT "id", "order date", "amount" FROM "user orders" WHERE "order date" > NOW() - INTERVAL '7 days'
Экранирование составных идентификаторов (схема.таблица)
Пример php
<?
$conn = pg_connect('dbname=test');
// Неправильный подход:
$fullName = 'public.user table';
$escapedWrong = pg_escape_identifier($conn, $fullName);
echo 'Неправильно: ' . $escapedWrong . '\n';
// Правильный подход:
$parts = explode('.', 'public.user table');
$escapedParts = array_map(fn($part) => pg_escape_identifier($conn, $part), $parts);
$escapedCorrect = implode('.', $escapedParts);
echo 'Правильно: ' . $escapedCorrect;
?>
Неправильно: "public.user table"
Правильно: "public"."user table"
Работа с идентификаторами в циклах
Пример php
<?
$conn = pg_connect('dbname=test');
$tables = ['sales_2024', 'user data', 'order-items'];
foreach ($tables as $table) {
    $escaped = pg_escape_identifier($conn, $table);
    $countQuery = 'SELECT COUNT(*) as cnt FROM ' . $escaped;
    echo $countQuery . '\n';
}
?>
SELECT COUNT(*) as cnt FROM "sales_2024"
SELECT COUNT(*) as cnt FROM "user data"
SELECT COUNT(*) as cnt FROM "order-items"

PHP pg_escape_identifier function comments

En
Pg escape identifier Escape a identifier for insertion into a text field