Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Depois de ter uma conexão funcionando no Getting started, use este guia para escrever, fazer commit e ler uma linha com qualquer uma das APIs do PHP. Cada programa inclui sua própria configuração e finalização. Use os links de tarefas para estender o fluxo de trabalho, em vez de copiar opções de uma API para outra.
Prepare uma conexão de teste
Use um banco de dados de teste do SQL Server existente e um login que possa se conectar e criar tabelas temporárias locais. Os exemplos usam autenticação SQL. Para opções de autenticação suportadas e onboarding sem senha do Azure, veja Conectando-se ao servidor.
Carregue a extensão que você escolher, defina SQL_SERVER, SQL_DATABASE, SQL_USER, e SQL_PASSWORD no ambiente do processo PHP.
SQL_SERVER pode incluir uma porta explícita, como <server>,1433. O servidor deve apresentar um certificado em que o cliente confia e válido para esse endpoint. Mantenha as senhas fora do programa e do controle de versão.
Armazene o nome real do banco de dados, nome de usuário e senha nas variáveis de ambiente. Cada programa dobra as chaves de fechamento e envolve esses valores em um único par de chaves para o manuseio da conexão no estilo ODBC do driver PHP. Escaping preserva caracteres especiais nos valores de conexão; não é parametrização de consulta. Para mais informações, veja Conectando ao servidor.
As instruções Transact-SQL (T-SQL) criam #PhpGuide, uma tabela temporária visível apenas para a conexão que a cria. Os programas não criam nem alteram uma tabela de aplicação permanente. Mantenha a mesma conexão durante todo o fluxo de trabalho.
Escreva e leia um registro
Os programas inserem um inteiro, texto UTF-8 e SQL NULL através de parâmetros. Eles exigem exatamente uma linha afetada, fazem commit na transação e verificam os valores retornados e os tipos de PHP. A consulta final também verifica se nenhuma transação permanece aberta.
SQLSRV
Salve este programa completo como workflow-sqlsrv.php, e execute 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
Salve esse programa separado como workflow-pdo.php, e execute 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;
Saída esperada para qualquer um dos programas:
Inserted 1 row; read committed UTF-8 text and null; no open transaction.
A saída só aparece depois que as verificações e a limpeza forem concluídas com êxito. Uma falha de conexão, escrita, busca, rollback ou limpeza de tabela gera uma exceção.
Entenda as escolhas
Use os marcadores de posição ? para valores em vez de concatenar os dados de entrada em T-SQL. Os exemplos mantêm os nomes das tabelas e colunas fixos: um parâmetro de valor não pode substituir um identificador. Instruções preparadas também permitem executar a mesma declaração novamente com valores diferentes. Para mais informações, veja Comparar funções de execução de consultas.
| Opção | Reason |
|---|---|
| Métodos explícitos de transação | O exemplo trata a escrita como uma unidade que deve ou confirmar ou desfazer. SQLSRV usa sqlsrv_begin_transaction, sqlsrv_commit, e sqlsrv_rollback; PDO usa seus próprios métodos de transação. |
| Descritores de parâmetros SQLSRV | Cada descritor especifica direção, tipo PHP e tipo SQL. As referências mantêm as variáveis de entrada, incluindo a variável que contém null. |
PDO bindValue |
A instrução recebe cada valor atual com um tipo explícito de parâmetro PDO.
bindParam é apropriado quando execuções posteriores precisam ler uma variável por referência. |
| UTF-8 mais nvarchar | PHP fornece bytes UTF-8; a extensão e o driver ODBC os convertem para a coluna SQL Unicode. O texto buscado deve corresponder à string PHP original byte por byte. |
| Busca numérica explícita para PDO | A comparação de resultados espera inteiros em PHP. Sem o atributo PDO_SQLSRV, esses resultados inteiros SQL usam a representação padrão do driver como cadeia de caracteres. |
| Chaves de busca nomeadas |
SQLSRV_FETCH_ASSOC e PDO::FETCH_ASSOC retorna arrays indexados pelo nome da coluna. As constantes da API não são intercambiáveis. |
PDO::exec para configuração da tabela |
Ele executa diretamente a instrução de criação de tabela. Essa abordagem evita criar uma tabela temporária dentro do escopo de uma instrução preparada pelo servidor. |
| Resultados somente de avanço | Os programas leem cada linha uma vez. Eles não solicitam um resultado bufferizado nem usam uma contagem de linhas de SELECT como prova de que a busca foi bem-sucedida. |
O SQLSRV retorna null quando seu array fetch chega ao fim e false em um erro de fetch. O fetch do PDO retorna false no final; com o modo de exceção configurado, um erro de busca do banco de dados lança uma exceção. Em ambas as APIs, o OptionalCount campo em si contém PHP null. Esse valor de campo não é um marcador de fim de resultados.
A operação de gravação faz commits antes da consulta de verificação. Se uma leitura posterior falhar, a gravação confirmada anterior não pode ser revertida. Neste exemplo, a linha pertence apenas a uma tabela temporária que a limpeza remove. Em uma aplicação com tabelas permanentes, reporte a falha com precisão e não repita um insert cegamente após um resultado de commit incerto.
Lidar com falhas e limpeza de recursos
O bloco catch reverte uma transação ativa e relança a exceção. O bloco finally libera a instrução, remove a tabela temporária e libera a conexão. A limpeza é executada no caminho de sucesso e no caminho de falha. Se o rollback ou a limpeza de tabelas também falharem, o programa preserva a exceção original como uma exceção anterior.
Para um exercício de linha de comando, uma exceção não capturada interrompe o PHP com um código de saída diferente de zero e uma mensagem de erro. Em uma aplicação web, capture isso no código que gerencia a solicitação. Remova valores sensíveis antes de registrar diagnósticos no seu registro de aplicação e retorne uma resposta de erro apropriada. Não exponha detalhes de conexão, credenciais ou erros brutos do banco de dados ao navegador.
| Failure | O que verificar |
|---|---|
| A função de extensão ou o driver está ausente | Confirme que o processo PHP carrega a extensão pretendida com o runtime e a configuração correspondentes. Uma configuração PHP funcional em linha de comando não prova que seu servidor web o utiliza. |
| Falha de conexão ou de certificado | Verifique o endpoint, autenticação, permissões e a confiança do certificado do cliente antes de mudar o código da consulta. Não desative a validação de certificados como solução de produção. |
| A tabela temporária não foi encontrada | Mantenha o estabelecimento, as gravações e as leituras em uma única conexão. Para a configuração do PDO, mantenha a abordagem demonstrada exec em vez de substituir por uma chamada preparada query padrão. |
| Valor inesperado ou tipo PHP | Verifique atributos de fetch e descritores de parâmetros. Não substitua asserções estritas por comparações flexíveis para esconder a diferença. |
| Falha ao gravar ou reverter | Capture imediatamente os erros do SQLSRV ou capture a exceção do PDO. Reporte falhas de rollback também; não diga que a escrita foi desfeita se o rollback falhou. |
| Falha na limpeza após perda de conexão | O programa não consegue confirmar a desconexão no servidor. Liberar os handles PHP não prova que a conexão física subjacente do pool fechou imediatamente. |
As extensões PHP fornecem as APIs de binding e fetch. O ODBC se comunica com o servidor e gerencia o pooling de conexões. O SQL Server controla o escopo de tabela temporária, transações, restrições e dados confirmados. Exclua a tabela explicitamente em vez de depender do fechamento da conexão física para a limpeza.
Depois do exercício, exclua workflow-sqlsrv.php e workflow-pdo.php se não precisar mais. Elimine as variáveis do ambiente de credencial do processo de teste quando terminar. Nenhum dos programas deixa uma tabela permanente para remover.
Esses guias passo a passo têm como alvo o SQL Server. Para Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure, Azure Synapse Analytics, banco de dados SQL no Fabric e Warehouse no Fabric, primeiro verifique a autenticação do destino e o suporte a T-SQL. Ambos os produtos Fabric exigem autenticação do Microsoft Entra ID, e o Warehouse requer que múltiplos conjuntos de resultados ativos (MARS) sejam desativados. Esses programas do SQL Server não estabelecem suporte específico do serviço a transações ou a tabelas temporárias.
Escolha sua próxima tarefa
Estenda o fluxo de trabalho com o item para o comportamento que você precisa.
| Tarefa | Guidance |
|---|---|
| Escolha autenticação ou gerencie conexões | Conectando ao servidor. |
| Reutilize uma instrução preparada com valores diferentes | Compare as funções de execução de consultas. |
| Escolha a execução direta ou preparada do PDO | Execução direta da declaração e execução da declaração preparada no driver PDO_SQLSRV. |
| Buscar valores e escolher formas de resultado | Recuperando dados. |
| Role ou coloque um resultado em buffer | Especificando um tipo de cursor e selecionando linhas. |
| Alterar dados do aplicativo | Atualizando dados. |
| Controlar conversões de tipos de PHP e SQL | Convertendo tipos de dados. |
| Diagnosticar falhas e habilitar o registro de drivers | Tratamento de erros e avisos e atividade de logging. |
| Proteger colunas sensíveis | Usando Always Encrypted com os drivers Microsoft para PHP para SQL Server. |
| Proteja uma aplicação em produção | Considerações de segurança para os drivers Microsoft para PHP para SQL Server. |