Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Nadat je een werkende verbinding hebt vanuit Getting Started, gebruik je deze gids om een rij te schrijven, te committen en te lezen met een van beide PHP API's. Elk programma heeft zijn eigen opstelling en opruiming. Gebruik de taaklinks om de workflow uit te breiden in plaats van opties van de ene API naar de andere te kopiëren.
Bereid een testverbinding voor
Gebruik een bestaande SQL Server-testdatabase en een login die verbinding maakt en lokale tijdelijke tabellen kan aanmaken. De voorbeelden gebruiken SQL-authenticatie. Voor ondersteunde authenticatiekeuzes en wachtwoordloze Azure-onboarding, zie Verbinden met de server.
Laad de extensie die je kiest en stel SQL_DATABASE, SQL_USER, SQL_PASSWORD en SQL_SERVER in in de omgeving van het PHP-proces.
SQL_SERVER kan een expliciete poort bevatten, zoals <server>,1433. De server moet een certificaat presenteren dat door de client wordt vertrouwd en geldig is voor dat endpoint. Houd wachtwoorden buiten het programma en versiebeheer.
Sla de daadwerkelijke databasenaam, gebruikersnaam en wachtwoord op in de omgevingsvariabelen. Elk programma verdubbelt sluitende beugels en sluit deze waarden één keer in beugels voor de ODBC-stijl aansluiting van de PHP-bestuurder. Escaping behoudt speciale tekens in verbindingswaarden; het is geen queryparameterisatie. Voor meer informatie, zie Verbinden met de server.
De Transact-SQL (T-SQL) statements creëren #PhpGuide, een tijdelijke tabel die alleen zichtbaar is voor de verbinding die het aanmaakt. De programma's maken of wijzigen geen permanente applicatietabel. Houd dezelfde verbinding gedurende de hele workflow.
Schrijf en lees een rij
De programma's voegen een geheel getal, UTF-8-tekst en SQL NULL in via parameters. Ze vereisen precies één getroffen rij, committen de transactie en verifiëren de geretourneerde waarden en PHP-types. De laatste query controleert ook of er geen transactie meer open is.
SQLSRV
Sla dit volledige programma op als workflow-sqlsrv.php, en voer php workflow-sqlsrv.php. uit
<?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
Sla dit aparte programma op als workflow-pdo.php, en voer php workflow-pdo.php uit.
<?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;
Verwachte output voor beide programma's:
Inserted 1 row; read committed UTF-8 text and null; no open transaction.
De output verschijnt pas nadat de controles en het opruimen zijn geslaagd. Een verbindings-, schrijf-, ophaal-, rollback- of table-cleanup-fout veroorzaakt in plaats daarvan een uitzondering.
Begrijp de keuzes
Gebruik ? placeholders voor waarden in plaats van invoer te concateneren in T-SQL. De voorbeelden houden de tabel- en kolomnamen vast: een waardeparameter kan een identificatie niet vervangen. Voorbereide statements laten je dezelfde statement ook opnieuw uitvoeren met verschillende waarden. Voor meer informatie, zie Query uitvoeringsfuncties vergelijken.
| Keuze | Reden |
|---|---|
| Expliciete transactiemethoden | Het voorbeeld behandelt de schrijfactie als een eenheid die ofwel moet committen of terugrollen. SQLSRV gebruikt sqlsrv_begin_transaction, sqlsrv_commit, en sqlsrv_rollback; PDO gebruikt zijn eigen transactiemethoden. |
| SQLSRV-parameterdescriptoren | Elke descriptor specificeert richting, PHP-type en SQL-type. Referenties behouden de invoervariabelen, inclusief de variabele die houdt null. |
PDO bindValue |
De instructie ontvangt elke huidige waarde met een expliciet PDO-parametertype.
bindParam is passend wanneer latere uitvoeringen een variabele via referentie moeten lezen. |
| UTF-8 plus nvarchar | PHP levert UTF-8-bytes; de extensie en ODBC-driver zetten deze om voor de SQL-Unicodekolom. De opgehaalde tekst moet overeenkomen met de originele PHP-string byte voor byte. |
| Expliciete numerieke ophalen voor PDO | De vergelijking van resultaten verwacht PHP-integers. Zonder het PDO_SQLSRV-attribuut gebruiken deze SQL-integerresultaten de standaardtekenreeksrepresentatie van de driver. |
| Benoemde fetch-sleutels |
SQLSRV_FETCH_ASSOC en PDO::FETCH_ASSOC return-arrays geïndexeerd op kolomnaam. De API-constanten zijn niet uitwisselbaar. |
PDO::exec voor tabelopstelling |
Het voert de instructie voor het maken van tabellen direct uit. Deze aanpak voorkomt het creëren van een tijdelijke tabel binnen de scope van een server-prepared statement. |
| Alleen-vooruitresultaten | De programma's lezen elke rij één keer. Ze vragen geen gebufferd resultaat op en gebruiken het aantal door SELECT geretourneerde rijen niet als bewijs dat het ophalen is geslaagd. |
SQLSRV keert terug null wanneer de array-ophaal het einde bereikt en false bij een ophaalfout. PDO's fetch retourneert aan het einde false; met de uitzonderingsmodus geconfigureerd wordt er een database-ophaalfout gegooid. In beide API's bevat het OptionalCount veld zelf PHP null. Die veldwaarde is geen markering voor het einde van de resultaten.
De schrijfbewerking wordt gecommit vóór de verificatiequery. Als een latere leesbewerking mislukt, kan de eerder doorgevoerde schrijfbewerking niet worden teruggedraaid. In dit voorbeeld hoort de rij alleen bij een tijdelijke tabel die door cleanup wordt verwijderd. Rapporteer in een applicatie met permanente tabellen de mislukking nauwkeurig en herhaal niet blindelings een insert na een onzekere commit-uitkomst.
Afhandelen van fouten en opschonen
Het catch blok rolt een actieve transactie terug en werpt de fout opnieuw op. Het finally blok geeft het statement vrij, laat de tijdelijke tabel vallen en maakt de verbinding los. Opschonen vindt plaats op het succespad en het foutpad. Als rollback of het opschonen van de tabel ook faalt, behoudt het programma de oorspronkelijke uitzondering als een eerdere uitzondering.
Voor een oefening op de opdrachtregel zorgt een niet-afgevangen uitzondering ervoor dat PHP stopt met een niet-nul exitcode en een foutmelding. In een webapplicatie kun je het opvangen in de code die het verzoek afhandelt. Verwijder gevoelige waarden voordat je diagnostiek in je applicatielogboek registreert en geef een passende foutrespons terug. Stel geen verbindingsgegevens, inloggegevens of ruwe databasefouten bloot aan de browser.
| Failure | Wat u moet controleren |
|---|---|
| De uitbreidingsfunctie of driver ontbreekt | Bevestig dat het PHP-proces de bedoelde extensie laadt met de bijbehorende runtime en configuratie. Een werkende commandoregel-PHP-configuratie bewijst niet dat je webserver het gebruikt. |
| Verbindings- of certificaatfout | Controleer het endpoint, de authenticatie, de rechten en het vertrouwen in het clientcertificaat voordat je de querycode wijzigt. Schakel certificaatvalidatie niet uit als oplossing in productie. |
| Kan tijdelijke tabel niet vinden | Houd de setup, schrijfbewerkingen en leesbewerkingen op één verbinding. Voor de PDO-opstelling houd je het gedemonstreerde exec pad aan in plaats van een standaard voorbereide query oproep te vervangen. |
| Onverwachte waarde of PHP-type | Controleer fetch-attributen en parameterdescriptors. Vervang strikte asserties niet door losse vergelijkingen om het verschil te verbergen. |
| Mislukte schrijf- of rollbackbewerking | Vang de fouten van SQLSRV direct vast, of leg de PDO-uitzondering vast. Rapporteer ook foute rollbacks; beweer niet dat het schrijven is ongedaan gemaakt als de rollback mislukte. |
| Schoonmaakfout na verbindingsverlies | Het programma kan de server-side drop niet bevestigen. Het vrijgeven van PHP-handles bewijst niet dat de onderliggende gepoolde fysieke verbinding direct gesloten is. |
De PHP-extensies bieden de binding- en fetch-API's. ODBC communiceert met de server en beheert de verbindingspooling. SQL Server beheert de scope, transacties, constraints en toegewezen data van tijdelijke tabels. Laat de tafel expliciet vallen in plaats van te vertrouwen op het sluiten van de fysieke verbinding voor opruiming.
Verwijder workflow-sqlsrv.php na de oefening en workflow-pdo.php als je ze niet meer nodig hebt. Verwijder de omgevingsvariabelen voor inloggegevens uit het testproces als je klaar bent. Geen van beide programma's laat een permanente tabel achter om te verwijderen.
Deze walkthroughs zijn gericht op SQL Server. Voor Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, SQL Database in Fabric en Warehouse in Fabric, controleer eerst de verificatie en T-SQL-ondersteuning van het doelsysteem. Beide Fabric-producten vereisen Microsoft Entra ID-authenticatie, en Warehouse vereist dat meerdere actieve resultaatsets (MARS) worden uitgeschakeld. Deze SQL Server-programma's brengen geen service-specifieke transacties of ondersteuning voor tijdelijke tabellen tot stand.
Uw volgende taak kiezen
Breid de workflow uit met het artikel voor het gedrag dat je nodig hebt.
| Task | Richtlijnen |
|---|---|
| Kies authenticatie of verbindingsbeheer | Verbinding maken met de server. |
| Hergebruik een prepared statement met andere waarden | Vergelijk query-uitvoeringsfuncties. |
| Kies voor directe uitvoering van PDO of uitvoering van prepared statements | Directe statementuitvoering en voorbereide statementuitvoering in de PDO_SQLSRV-driver. |
| Haal waarden op en kies resultaatvormen | Data wordt opgehaald. |
| Scroll of plaats een resultaat in de buffer | Een cursortype specificeren en rijen selecteren. |
| Applicatiegegevens wijzigen | Data bijwerken. |
| Beheer PHP- en SQL-typeconversies | Gegevenstypen converteren. |
| Diagnoseer storingen en schakel driverlogging in | Afhandelen van fouten en waarschuwingen en logactiviteiten. |
| Bescherm gevoelige kolommen | Always Encrypted gebruiken met de Microsoft-drivers voor PHP voor SQL Server. |
| Beveiligen van een productieapplicatie | Beveiligingsoverwegingen voor de Microsoft Drivers voor PHP voor SQL Server. |