Backup do banco de dados SQL Server usando PHP

Sep 22 2020

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

Zhorov Sep 24 2020 at 07:46

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 das BACKUP\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ão sqlsrv_next_result()(para a versão SQLSRV do driver) e PDOStatement::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;
?>