Backup do banco de dados SQL Server usando PHP
Estou tentando fazer backup de um banco de dados MS SQL chamando um procedimento armazenado usando PHP.
Quando executo o SP no SSMS, tudo funciona bem. No entanto, quando eu o chamo a partir do script PHP, posso ver um ".bak" na pasta de backup e logo após o PHP terminar o processamento, o arquivo BackUp.bak desaparece.
Aqui está o procedimento armazenado:
DECLARE @date VARCHAR(10)
SET @date = (SELECT date FROM tbl_date)
Declare @fileName VARCHAR(100)
SET @fileName = ('C:\db_backup\BackUp_' + @date + '.bak')
BACKUP DATABASE DbName
TO DISK = @fileName
WITH FORMAT,
MEDIANAME = 'SQLServerBackups',
NAME = 'Full Backup of DbName';
Abaixo está o código PHP que chamo de SP:
$serverName = "server"; $connectionInfo = array( "Database"=>"DbName", "UID"=>"UserName", "PWD"=>"P@ssword", "CharacterSet"=>"UTF-8", "ReturnDatesAsStrings" => "false");
$conn = sqlsrv_connect( $serverName, $connectionInfo); $BackupDB = "Exec DBBackup";
sqlsrv_query($conn, $BackupDB);
Estou executando o Apache 2.4.46 e o SQL Server Express 2019.
Meu objetivo é criar um arquivo ".bak" usando PHP.
Tentei usar um SP porque o código original é escrito em Classic ASP e funciona perfeitamente assim.
Estou aberto para experimentar diferentes abordagens.
Obrigado.
Respostas
Explicações:
Você está usando o driver PHP para SQL Server, portanto, as seguintes explicações são uma opção adicional para resolver seu problema:
- Parece que esse problema é provavelmente um problema específico do driver. O SQL Server preenche o buffer de saída da conexão com os conjuntos de resultados criados pelo lote - informações sobre a contagem das linhas afetadas (em um caso de
INSERT\DELETE\UPDATEinstruções, por exemplo) ou status de progresso (retornado dasBACKUP\RESTORE DATABADEinstruções). Esses conjuntos de resultados devem ser processados pelo script PHP. Parece que esse comportamento é intencional e o script PHP deve liberar todos os conjuntos de resultados pendentes. Depois que os conjuntos de resultados são buscados, o SQL Server conclui a execução do lote. As funções \ métodos apropriados que você precisa usar sãosqlsrv_next_result()(para a versão SQLSRV do driver) ePDOStatement::nextRowset()(para a versão PDO_SQLSRV do driver). - Para a versão SQLSRV do driver, você precisa alterar o tratamento de erros e avisos usando
sqlsrv_configure("WarningsReturnAsErrors", 0);.
Exemplos:
Consigo reproduzir o problema da pergunta e os exemplos a seguir são soluções úteis:
Usando a versão SQLSRV do driver:
<?php
// Server information
$server = "server\instance,port"; $database = "database";
$uid = "username"; $pwd = "password";
// Configuration
sqlsrv_configure("WarningsReturnAsErrors", 0);
// Connection
$cinfo = array( "UID" => $uid,
"PWD" => $pwd, "Database" => $database
);
$conn = sqlsrv_connect($server, $cinfo); if ($conn === false) {
echo "Unable to connect.";
die( print_r( sqlsrv_errors(), true));
}
// Statement
$sql = " DECLARE @date VARCHAR(19) SET @date = CONVERT(VARCHAR(19), GETDATE(), 126) SET @date = REPLACE(@date, ':', '-') SET @date = REPLACE(@date, 'T', '-') DECLARE @fileName VARCHAR(100) SET @fileName = ('d:\backup\BackUp_' + @date + '.bak') BACKUP DATABASE dbname TO DISK = @fileName WITH FORMAT, STATS = 1, MEDIANAME = 'SQLServerBackups', NAME = 'Full Backup of dbname'; "; $stmt = sqlsrv_query($conn, $sql);
if ($stmt === false) { echo "Unable to execute query."; die( print_r( sqlsrv_errors(), true)); } // Clear buffer while (sqlsrv_next_result($stmt) != null){};
echo "Success";
// End
sqlsrv_free_stmt($stmt); sqlsrv_close($conn);
?>
Usando a versão PDO_SQLSRV do driver:
<?php
// Server information
$server = "server\instance,port"; $database = "database";
$uid = "username"; $pwd = "password";
// Connection
try {
$conn = new PDO("sqlsrv:server=$server;Database=$database", $uid, $pwd); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) { die( "Error connecting to SQL Server".$e->getMessage());
}
// Statement
$sql = " DECLARE @date VARCHAR(19) SET @date = CONVERT(VARCHAR(19), GETDATE(), 126) SET @date = REPLACE(@date, ':', '-') SET @date = REPLACE(@date, 'T', '-') DECLARE @fileName VARCHAR(100) SET @fileName = ('d:\backup\BackUp_' + @date + '.bak') BACKUP DATABASE dbname TO DISK = @fileName WITH FORMAT, STATS = 1, MEDIANAME = 'SQLServerBackups', NAME = 'Full Backup of dbname'; "; try { $stmt = $conn->prepare($sql);
$stmt->execute(); } catch (PDOException $e) {
die ("Error executing query. ".$e->getMessage()); } // Clear buffer try { while ($stmt->nextRowset() != null){};
echo "Success";
} catch (PDOException $e) { die ("Error executing query. ".$e->getMessage());
}
// End
$stmt = null; $conn = null;
?>