Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poté, co budete mít funkční připojení v Getting started, použijte tento průvodce k napsání, potvrzení zápisu a čtení řádku pomocí některého z rozhraní PHP API. Každý program obsahuje vlastní nastavení a vyčištění. Použijte odkazy úloh k rozšíření pracovního postupu místo kopírování možností z jednoho API do druhého.
Připravte testovací připojení
Použijte existující testovací databázi SQL Serveru a přihlašovací účet, který se může připojit a vytvářet lokální dočasné tabulky. Příklady používají SQL autentizaci. Pro podporované možnosti autentizace a onboarding Azure bez hesla viz Připojení k serveru.
Načtěte zvolené rozšíření a v prostředí procesu PHP nastavte SQL_SERVER, SQL_USER, SQL_PASSWORD a SQL_DATABASE.
SQL_SERVER může obsahovat explicitní port, například <server>,1433. Server musí předložit certifikát, kterému klient důvěřuje a který je platný pro daný koncový bod. Hesla mějte mimo program a správu zdrojového kódu.
Uložte skutečné jméno databáze, uživatelské jméno a heslo do proměnných prostředí. Každý program zdvojí zavírací závorky a tyto hodnoty uzavře jednou do složených závorek pro ODBC-stylové zpracování spojení v PHP ovladači. Escaping zachovává speciální znaky v hodnotách spojení; nejde o parametrizaci dotazů. Pro více informací viz Připojení k serveru.
Příkazy Transact-SQL (T-SQL) vytvářejí #PhpGuide, dočasnou tabulku viditelnou pouze pro spojení, které ji vytvoří. Programy nevytvářejí ani nemění trvalou aplikační tabulku. Udržujte stejné připojení po celou dobu pracovního postupu.
Zapsat a přečíst řádek
Programy vkládají celočíselné číslo, text UTF-8 a SQL NULL prostřednictvím parametrů. Vyžadují přesně jeden ovlivněný řádek, commitují transakci a ověřují vrácené hodnoty a typy PHP. Závěrečný dotaz také kontroluje, že žádná transakce nezůstane otevřená.
SQLSRV
Uložte tento kompletní program jako workflow-sqlsrv.php a spusťte php workflow-sqlsrv.php.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$conn = sqlsrv_connect($config['SQL_SERVER'], [
'Database' => $config['SQL_DATABASE'],
'UID' => $config['SQL_USER'],
'PWD' => $config['SQL_PASSWORD'],
'Encrypt' => true,
'TrustServerCertificate' => false,
'LoginTimeout' => 30,
'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$stmt = null;
$inTransaction = false;
$failure = null;
try {
$stmt = sqlsrv_query($conn, 'CREATE TABLE #PhpGuide '
. '(Id int PRIMARY KEY, Title nvarchar(80), OptionalCount int NULL)');
if ($stmt === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
sqlsrv_free_stmt($stmt);
$stmt = null;
if (!sqlsrv_begin_transaction($conn)) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$inTransaction = true;
$id = 1;
$title = "Caf\u{00E9}";
$optionalCount = null;
$params = [
[&$id, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT],
[&$title, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('UTF-8'), SQLSRV_SQLTYPE_NVARCHAR(80)],
[&$optionalCount, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT],
];
$stmt = sqlsrv_prepare($conn,
'INSERT INTO #PhpGuide (Id, Title, OptionalCount) VALUES (?, ?, ?)', $params);
if ($stmt === false || !sqlsrv_execute($stmt)) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$affected = sqlsrv_rows_affected($stmt);
if ($affected === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
if ($affected !== 1) {
throw new RuntimeException('Expected exactly one inserted row.');
}
sqlsrv_free_stmt($stmt);
$stmt = null;
if (!sqlsrv_commit($conn)) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$inTransaction = false;
$stmt = sqlsrv_query($conn,
'SELECT Id, Title, OptionalCount, @@TRANCOUNT AS TransactionCount FROM #PhpGuide');
if ($stmt === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($row === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
if ($row !== ['Id' => 1, 'Title' => $title, 'OptionalCount' => null, 'TransactionCount' => 0]) {
throw new RuntimeException('Unexpected committed values, types, or transaction state.');
}
$end = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($end === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
if ($end !== null) {
throw new RuntimeException('Expected exactly one result row.');
}
} catch (Throwable $error) {
$failure = $error;
if ($inTransaction && !sqlsrv_rollback($conn)) {
$failure = new RuntimeException(
'Rollback failed: ' . print_r(sqlsrv_errors(), true), 0, $error);
}
throw $failure;
} finally {
if (is_resource($stmt)) {
sqlsrv_free_stmt($stmt);
}
try {
$cleanup = sqlsrv_query($conn, 'DROP TABLE IF EXISTS #PhpGuide');
if ($cleanup === false) {
throw new RuntimeException(
'Cleanup failed: ' . print_r(sqlsrv_errors(), true), 0, $failure);
}
sqlsrv_free_stmt($cleanup);
} finally {
sqlsrv_close($conn);
}
}
echo "Inserted 1 row; read committed UTF-8 text and null; no open transaction.", PHP_EOL;
PDO_SQLSRV
Uložte tento samostatný program jako workflow-pdo.php a spusťte php workflow-pdo.php.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$pdo = new PDO(
"sqlsrv:Server=$server;Database=$database;Encrypt=true;"
. "TrustServerCertificate=false;LoginTimeout=30",
$config['SQL_USER'],
$config['SQL_PASSWORD'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true,
]
);
$stmt = null;
$failure = null;
try {
$pdo->exec('CREATE TABLE #PhpGuide '
. '(Id int PRIMARY KEY, Title nvarchar(80), OptionalCount int NULL)');
$pdo->beginTransaction();
$title = "Caf\u{00E9}";
$stmt = $pdo->prepare(
'INSERT INTO #PhpGuide (Id, Title, OptionalCount) VALUES (?, ?, ?)');
$stmt->bindValue(1, 1, PDO::PARAM_INT);
$stmt->bindValue(2, $title, PDO::PARAM_STR);
$stmt->bindValue(3, null, PDO::PARAM_NULL);
$stmt->execute();
if ($stmt->rowCount() !== 1) {
throw new RuntimeException('Expected exactly one inserted row.');
}
$stmt = null;
$pdo->commit();
$stmt = $pdo->query(
'SELECT Id, Title, OptionalCount, @@TRANCOUNT AS TransactionCount FROM #PhpGuide');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row !== ['Id' => 1, 'Title' => $title, 'OptionalCount' => null, 'TransactionCount' => 0]) {
throw new RuntimeException('Unexpected committed values, types, or transaction state.');
}
if ($stmt->fetch(PDO::FETCH_ASSOC) !== false || $pdo->inTransaction()) {
throw new RuntimeException('Expected one result row and no open transaction.');
}
} catch (Throwable $error) {
$failure = $error;
if ($pdo->inTransaction()) {
try {
$pdo->rollBack();
} catch (PDOException $rollbackError) {
$failure = new RuntimeException(
'Rollback failed: ' . $rollbackError->getMessage(), 0, $error);
}
}
throw $failure;
} finally {
$stmt = null;
try {
$pdo->exec('DROP TABLE IF EXISTS #PhpGuide');
} catch (PDOException $cleanupError) {
throw new RuntimeException(
'Cleanup failed: ' . $cleanupError->getMessage(), 0, $failure ?? $cleanupError);
} finally {
$pdo = null;
}
}
echo "Inserted 1 row; read committed UTF-8 text and null; no open transaction.", PHP_EOL;
Očekávaný výstup pro kterýkoli z obou programů:
Inserted 1 row; read committed UTF-8 text and null; no open transaction.
Výstup se objeví až po úspěšných kontrolách a úklidu. Selhání spojení, zápisu, načítání, rollbacku nebo čištění tabulky místo toho vyvolá výjimku.
Pochopte volby
Používejte ? zástupné symboly pro hodnoty místo spojování vstupů do T-SQL. Příklady udržují názvy tabulek a sloupců pevné: hodnotový parametr nemůže nahradit identifikátor. Připravené příkazy vám také umožní znovu provést stejný příkaz s různými hodnotami. Pro více informací viz Porovnávání funkcí pro provádění dotazů.
| Výběr | Reason |
|---|---|
| Explicitní transakční metody | V příkladu se se zápisem zachází jako s jednotkou, kterou je nutné buď potvrdit, nebo vrátit změny. SQLSRV používá sqlsrv_begin_transaction, sqlsrv_commit a sqlsrv_rollback; PDO používá vlastní transakční metody. |
| Parametrové deskriptory SQLSRV | Každý deskriptor specifikuje směr, typ PHP a typ SQL. Reference si zachovávají vstupní proměnné, včetně proměnné, která obsahuje null. |
PDO bindValue |
Příkaz přijímá každou hodnotu s explicitním typem parametru PDO.
bindParam je vhodné, když pozdější provádění musí číst proměnnou přes referenci. |
| UTF-8 plus nvarchar | PHP poskytuje bajty UTF-8; rozšíření a ODBC ovladač je převádějí pro sloupec SQL Unicode. Načítaný text musí odpovídat původnímu PHP řetězci bajt po bajtu. |
| Explicitní numerické načítání pro PDO | Porovnání výsledků očekává celá čísla v PHP. Bez atributu PDO_SQLSRV tyto SQL celočíselné výsledky používají výchozí reprezentaci řetězců ovladače. |
| Pojmenované klíče fetch |
SQLSRV_FETCH_ASSOC a PDO::FETCH_ASSOC vracejí pole indexovaná podle názvu sloupce. API konstanty nejsou zaměnitelné. |
PDO::exec pro nastavení tabulky |
Přímo vykonává příkaz pro tvorbu tabulky. Tento přístup se vyhýbá vytváření dočasné tabulky v rámci příkazu připraveného serverem. |
| Výsledky pouze vpřed | Programy čtou každý řádek jednou. Nepožadují bufferovaný výsledek ani nepoužívají počet řádků SELECT jako důkaz, že načtení bylo úspěšné. |
SQLSRV vrátí null, když načítání z pole dosáhne konce, a false při chybě načítání. Na konci se vrátí fetch false v PDO; při nastavení režimu výjimky dojde při chybě načtení z databáze k vyvolání výjimky. V obou API OptionalCount pole samo obsahuje PHP null. Tato hodnota pole není ukazatelem konce výsledků.
Zápis se commituje před ověřovacím dotazem. Pokud pozdější čtení selže, dříve potvrzený zápis nelze vrátit zpět. V tomto příkladu řádek patří pouze do dočasné tabulky, kterou cleanup odstraní. V aplikaci s trvalými tabulkami nahlaste selhání přesně a neopakujte naslepo vložení po nejistém výsledku commitu.
Zpracování selhání a vyčištění
Blok catch provede rollback aktivní transakce a znovu vyhodí selhání. Blok finally uvolní příkaz SQL, zruší dočasnou tabulku a uvolní připojení. Úklid probíhá při úspěšném i neúspěšném průběhu. Pokud selže i rollback nebo čištění tabulky, program zachová původní výjimku jako předchozí výjimku.
Při spuštění z příkazové řádky zastaví nechycená výjimka PHP nenulovým výstupním kódem a chybovou zprávou. V webové aplikaci to zachyťte v kódu, který zpracovává požadavek. Odstraňte citlivé hodnoty před zaznamenáním diagnostiky do aplikačního logu a vraťte odpovídající chybovou odpověď. Nevystavujte prohlížeči podrobnosti o připojení, přihlašovací údaje ani nezpracované chybové hlášky databáze.
| Selhání | Co zkontrolovat |
|---|---|
| Chybí funkce rozšíření nebo ovladač | Potvrďte, že PHP proces načte zamýšlené rozšíření s odpovídajícím runtime a konfigurací. Funkční konfigurace PHP příkazového řádku nedokazuje, že ji váš webový server používá. |
| Selhání připojení nebo certifikátu | Před změnou kódu dotazu zkontrolujte koncový bod (endpoint), autentizaci, oprávnění a důvěru v klientské certifikáty. Nedeaktivujte ověřování certifikátů jako řešení pro produkční prostředí. |
| Dočasná tabulka není nalezena | Udržujte nastavení, zápisy a čtení na jednom připojení. Pro nastavení PDO zachovejte demonstrovaný postup exec místo nahrazení výchozím připraveným voláním query. |
| Neočekávaná hodnota nebo typ PHP | Zkontrolujte atributy fetch a popisy parametrů. Nenahrazujte striktní aserce volným porovnáváním, abyste skryli rozdíl. |
| Neúspěch zápisu nebo vrácení změn | Okamžitě zachyťte chyby SQLSRV, jinak dojde k výjimce PDO. Hláste také selhání rollbacku; netvrdíte, že zápis byl zrušen, pokud rollback selhal. |
| Selhání čištění po ztrátě spojení | Program nemůže potvrdit odpojení na serveru. Uvolnění obslužných rutin PHP nedokazuje, že základní fyzické připojení z fondu bylo okamžitě uzavřeno. |
PHP rozšíření poskytují API pro propojení a načítání. ODBC komunikuje se serverem a spravuje poolování spojení. SQL Server řídí rozsah dočasných tabulek, transakce, omezení a potvrzená data. Vypněte stůl explicitně, místo abyste spoléhali na fyzické uzavření spojení při úklidu.
Po cvičení je smažte workflow-sqlsrv.php a workflow-pdo.php pokud už je nepotřebujete. Po dokončení testu vymažte proměnné prostředí přihlašovacích údajů z procesu testování. Ani jeden z těchto programů nezanechává trvalou tabulku k odstranění.
Tyto návody cílí na SQL Server. Pro Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, SQL database in Fabric a Warehouse in Fabric nejprve zkontrolujte ověřování cíle a podporu T-SQL. Oba produkty Fabric vyžadují autentizaci Microsoft Entra ID a Warehouse vyžaduje deaktivaci více aktivních sad výsledků (MARS). Tyto programy SQL Server nezajišťují podporu transakcí ani dočasných tabulek specifických pro službu.
Vyberte si další úkol
Rozšiřte pracovní postup o článek pro chování, které potřebujete.
| Task | Průvodce |
|---|---|
| Vyberte ověřování nebo spravujte připojení | Připojování k serveru. |
| Znovu použijte připravený příkaz s různými hodnotami | Porovnejte funkce pro provádění dotazů. |
| Vyberte si přímé nebo připravené spuštění s PDO | Přímé provedení příkazu a připravené provedení příkazu v ovladači PDO_SQLSRV. |
| Načíst hodnoty a zvolit podoby výsledků | Načítání dat. |
| Posuňte nebo uložte výsledek do vyrovnávací paměti | Specifikace typu kurzoru a výběr řádků. |
| Změnit aplikační data | Probíhá aktualizace dat. |
| Řízení převodů typů v PHP a SQL | Převod datových typů. |
| Diagnostikujte selhání a povolte logování ovladačů | Zpracování chyb a varování a zaznamenání aktivity. |
| Chraňte citlivé sloupce | Používání Always Encrypted s Microsoft ovladači pro PHP pro SQL Server. |
| Zabezpečte produkční aplikaci | Bezpečnostní aspekty pro ovladače Microsoftu pro PHP pro SQL Server. |