Copia de seguridad de la base de datos de SQL Server usando PHP

Sep 22 2020

Estoy intentando hacer una copia de seguridad de una base de datos MS SQL llamando a un procedimiento almacenado usando PHP.

Cuando ejecuto de SP en SSMS, todo funciona bien. Sin embargo, cuando lo llamo desde el script PHP, puedo ver un ".bak" en la carpeta de respaldo y justo después de que PHP termina de procesarse, el archivo BackUp.bak desaparece.

Aquí está el procedimiento almacenado:

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';

A continuación se muestra el código PHP que llamo 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);

Estoy ejecutando Apache 2.4.46 y SQL Server Express 2019.

Mi objetivo es crear un archivo ".bak" usando PHP.

Intenté usar un SP porque el código original está escrito en ASP clásico y funciona perfectamente de esta manera.

Estoy abierto a probar diferentes enfoques.

Gracias.

Respuestas

Zhorov Sep 24 2020 at 07:46

Explicaciones:

Está utilizando el controlador PHP para SQL Server, por lo que las siguientes explicaciones son una opción adicional para resolver su problema:

  • Parece que este problema es probablemente un problema específico del controlador. SQL Server llena el búfer de salida de la conexión con los conjuntos de resultados creados por el lote: información sobre el recuento de las filas afectadas (en el caso de INSERT\DELETE\UPDATEdeclaraciones, por ejemplo) o el estado de progreso (devuelto por BACKUP\RESTORE DATABADEdeclaraciones). Estos conjuntos de resultados deben ser procesados ​​por el script PHP. Parece que este comportamiento es por diseño y el script PHP debería eliminar todos los conjuntos de resultados pendientes. Una vez que se obtienen los conjuntos de resultados, SQL Server completa la ejecución del lote. Las funciones / métodos apropiados que necesita utilizar son sqlsrv_next_result()(para la versión SQLSRV del controlador) y PDOStatement::nextRowset()(para la versión PDO_SQLSRV del controlador).
  • Para la versión SQLSRV del controlador, debe cambiar el manejo de errores y advertencias usando sqlsrv_configure("WarningsReturnAsErrors", 0);.

Ejemplos:

Puedo reproducir el problema de la pregunta y los siguientes ejemplos son soluciones que funcionan:

Usando la versión SQLSRV del controlador:

<?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 la versión PDO_SQLSRV del controlador:

<?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;
?>