Length of output parameter in sqlsrv - 01004 (Data truncated) - php

I have stored procedures in SQL Server that output data as xml datatype. When I try to get the output parameter in PHP with PHP Driver for SQL Server (sqlsrv extension) and the string is longer than 4000 I get an SQL Error (SQLSTATE 01004 (Data truncated)).
Here is a short example:
Stored Procedure:
CREATE PROCEDURE pr_getlargexml
#xml xml OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET #xml =
(
SELECT *
FROM largeTable
FOR XML RAW, ELEMENTS, TYPE, ROOT('xml')
);
END;
GO
PHP code:
$serverName = "localhost\SQL2012TEST";
$connectionInfo = array("Database" => "TEST", "UID" => "", "PWD" => "");
$conn = sqlsrv_connect($serverName, $connectionInfo);
if ($conn === false) {
die(print_r(sqlsrv_errors(), true));
}
$retval = '';
$query = sqlsrv_query($conn, 'EXEC pr_getlargexml ?',array(array(&$retval,SQLSRV_PARAM_OUT,SQLSRV_PHPTYPE_STRING('UTF-8'),SQLSRV_SQLTYPE_XML)));
if ($query === false) {
die(print_r(sqlsrv_errors(), true));
}
echo "<pre>";
\var_dump($retval);
echo "</pre>";
If the xml is shorter than 4000, it works fine. I also tried to use nvarchar(max) as datatype in sql and SQLSRV_SQLTYPE_NVARCHAR('max') in php as sqltype, but I get the same Error.
Has anyone a solution for my problem?

Related

php - how execute a sqlsrv stored procedure

I have a successful connection to SQL Server using SQLSRV in my PHP script:
$name = 'SERVERNAME';
$db = 'DBNAME';
$par = array("Database"=>$db);
$conn = sqlsrv_connect($name, $par);
Also I have the following T-SQL script:
Declare #dt datetime;
SET #dt = GETDATE();
EXEC oik..SrezLTGES #Cat = 'Ë', #Ids = '140539,140540,140589,150395,180395,180396,180445',#Time = #dt
The procedure parameters are:
I don't know how to execute this query in PHP. Any ideas?
A possible approach here is to parameterize the statement and use sqlsrv_query(). As is mentioned in the documentation, the sqlsrv_query function is well-suited for one-time queries and should be the default choice to execute queries unless special circumstances apply and sqlsrv_query function does both statement preparation and statement execution, and can be used to execute parameterized queries.
The stored procedure has varchar parameters (and I'm almost sure, that you are using a cyrillic collation), so you may need to use the appropriate encoding ("CharacterSet" => "UTF-8" or "CharacterSet" => SQLSRV_ENC_CHAR in the connection options) and/or character set conversion on the parameters values (with iconv() for example). Reading UTF-8 all the way through is a good starting point.
If the stored procedure returns data, you may try to use sqlsrv_fetch_array() to retrieve the returned data. You may also use SET NOCOUNT ON to prevent SQL Server from passing the count of the affected rows as part of the result set.
The following example, based on your code, is a possible solution to your problem:
<?php
// Connection
$server = "SERVERNAME";
$database = "DBNAME";
$cinfo = array(
"CharacterSet" => "UTF-8",
"Database" => $database
);
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
// Statement
$sql = "
SET NOCOUNT ON;
DECLARE #dt datetime;
SET #dt = GETDATE();
EXEC oik..SrezLTGES
#Cat = ?,
#Ids = ?,
#Time = #dt,
#TimeIsSummer = 1,
#ShowSystemTime = 1
";
$params = array("Ë", "140539,140540,140589,150395,180395,180396,180445");
$stmt = sqlsrv_query($con, $sql, $params);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// Data
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
echo print_r($row, true);
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
?>

Backup SQL Server database using PHP

I am trying to backup a MS SQL database calling a Stored Procedure using PHP.
When I execute de SP on SSMS, everything works fine. However, when I call it from the PHP script, I can see a ".bak" in the backup folder and right after the PHP finishes processing, the BackUp.bak file disappears.
Here is the Stored Procedure:
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';
Below is the PHP code I call the 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);
I am running Apache 2.4.46 and SQL Server Express 2019.
My goal is to create a ".bak" file using PHP.
I tried using a SP because the original code is written in Classic ASP and it works flawlessly this way.
I am open to try different approaches.
Thank you.
Explanations:
You are using PHP Driver for SQL Server, so the following explanations are an additional option for solving your problem:
It seems that this issue is probably a driver specific problem. SQL Server fills the output buffer of the connection with the result sets that are created by the batch - information about the count of the affected rows (in a case of INSERT\DELETE\UPDATE statements for example) or progress status (returned from BACKUP\RESTORE DATABADE statements). These result sets must be processed by the PHP script. It seems that this behavior is by design and the PHP script should flush all the pending result sets. After the result sets are fetched, SQL Server completes the execution of the batch. The appropriate functions\methods that you need to use are sqlsrv_next_result() (for SQLSRV version of the driver) and PDOStatement::nextRowset() (for PDO_SQLSRV version of the driver).
For the SQLSRV version of the driver you need to change the error and warning handling using sqlsrv_configure("WarningsReturnAsErrors", 0);.
Examples:
I'm able to reproduce the issue from the question and the following examples are working solutions:
Using SQLSRV version of the 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);
?>
Using PDO_SQLSRV version of the 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;
?>

WAMP localhost install SQLSRV for connecting to database

I'm using WAMP to run my code locally.
Now I want to connect to a microsoft SQL server database using PHP.
// connection with callstats DB
$serverName = "IP, 1433"; //serverName\instanceName, portNumber (default is 1433)
$connectionInfo = array( "Database"=>"CDR", "UID"=>"username", "PWD"=>"password");
Im using:
$conn_CDR = sqlsrv_connect( $serverName, $connectionInfo);
$params = array();
And then for a query:
$result = sqlsrv_query($conn_CDR, "", $params);
But then I get this error:
Warning: sqlsrv_query() expects parameter 1 to be resource, boolean given
Now I know I need to install sqlsrv into my localhost.
I'm using PHP 7.2.14 so I installed php_sqlsrv_72_ts.dll to my C:\localhost\bin\php\php7.2.14.
Also I added this line to my php.ini.
extension=php_sqlsrv_72_ts.dll
Then I restarted my WAMPserver, and runned my code again, but I still get the same result.
I also tried adding the file to C:\localhost\bin\apache\apache2.4.37\binbut no succes either.
Does anyone know why this error keeps occurring and how to fix it?
I solved it by installing the Microsoft ODBC Driver for SQL Server onto my computer.
Then I restarted my WAMP server and it worked!
Download ODBC Driver here
This gave me the info I needed to solve my error:
if ($conn_CDR === false) {echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);}
$conn_CDR = sqlsrv_connect( $serverName, $connectionInfo);
$params = array();
$sql = "your sql query";
$result = sqlsrv_query($conn_CDR, $sql, $params));
See the manual here https://www.php.net/manual/en/function.sqlsrv-query.php
like this example:-
$sql = "INSERT INTO Table_1 (id, data) VALUES (?, ?)";
$params = array(1, "some data");
$stmt = sqlsrv_query( $conn, $sql, $params);
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true));
}

UPDATE VARBINARY(MAX) column in SQL Server table with $_FILE image upload

I've been looking all across the internet for help on this and have found nothing.
Basically I need to know how to update a SQL Server VARBINARY(MAX) column with the hex of an image uploaded from a HTML form. The database is in a different place to the HTML form, so move_uploaded_file in PHP then OPENROWSET (BULK ...) in SQL doesn't work (unable to find the file).
I also tried doing file_get_contents on the uploaded $_FILE['name_']['tmp_name'], then used unpack("H*hex") and put the result of that into the SQL column with a "0x" prepend, but that crashes, saying it needs to be converted from a VARCHAR to a VARBINARY. When I convert it, the code runs and the column is populated, but the image is malformed.
No idea what to do next. Pls help.
Solution:
This is a basic approach using PHP Driver for SQL Server:
Table creation (T-SQL):
CREATE TABLE [dbo].[ImageTable] (
[ImageData] varbinary(max) NULL
)
PHP:
<?php
# Connection
$server = 'server\instance,port';
$database = 'database';
$uid = 'user';
$pwd = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $uid,
"PWD" => $pwd
);
$conn = sqlsrv_connect($server, $cinfo);
if( $conn === false )
{
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
# Update image using CONVERT()
$image = file_get_contents('image.jpg');
$sql = "UPDATE ImageTable SET [ImageData] = CONVERT(varbinary(max), ?) WHERE (yor_update_condition)";
$params = array(
array($image, SQLSRV_PARAM_IN)
);
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
# End
echo 'Image updated.'
?>

Executing a simple SQL Server stored procedure from php

First of all: I did a research on google and stackoverflow, but it does not helped me.
I'm a beginner, so please do not blame me directly by just reading the title and voting me down. Stackoverflow seems to be very aggressive sometimes :(
I'm trying to execute a simple stored procedure from PHP.
Connecting to the database works.
This code also works through a query in SQL Server Management Studio:
Execute SP_TPL_DeleteUser
#ExternalFieldID = 22
Regarding to this manuals: PHP Stored Procedures and SQL Server and MSSQL Bind
I build this lines of code:
$id=22;
$stmt=mssql_init("SP_TPL_DeleteUser", $conn);
mssql_bind($stmt, "#ExternalFieldID", $ExternalFieldID, SQLVARCHAR, false, false, 255);
mssql_execute($stmt);
mssql_free_statement($stmt);
My output is:
( ! ) Fatal error: Call to undefined function mssql_init() in
C:\Users\kians_000\dev\traka\index.php on line 32
Of course I tried playing around, but nothing works :(
I would be thankful for any tips.
Edit:
I can connect to the DB with this:
$serverName = "KIAN-PC";
$connectionInfo = array( "Database"=>"T32Database");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn )
{
echo "Connection established.\n";
}
else
{
echo "Connection could not be established.\n";
die( print_r( sqlsrv_errors(), true));
}
But a simple query like this:
$version = mssql_query('SELECT * FROM [T32Database].[dbo].[TUsers]');
$row = mssql_fetch_array($version);
echo $row[0];
Produces this output:
Fatal error: Call to undefined function mssql_query() in C:\Users\kians_000\dev\traka\index.php on line 42
phpinfo show me this:
sqlsrv
sqlsrv support enabled
Directive Local Value Master Value
sqlsrv.ClientBufferMaxKBSize 10240 10240 sqlsrv.LogSeverity 0 0
sqlsrv.LogSubsystems 0 0 sqlsrv.WarningsReturnAsErrors On On
Edit 3:
I tried out all drivers. This is the only one that works.
Maybe something with my source is wrong.
<?php
//-----------------------------------------------
// Connect to SQL Server DB
//-----------------------------------------------
$serverName = "KIAN-PC";
$connectionInfo = array( "Database"=>"T32Database");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn )
{
echo "Connection established.\n";
}
else
{
echo "Connection could not be established.\n";
die( print_r( sqlsrv_errors(), true));
}
//-----------------------------------------------
// Perform operations with connection.
//-----------------------------------------------
$version = mssql_query('SELECT * FROM [T32Database].[dbo].[TUsers]');
$row = mssql_fetch_array($version);
echo $row[0];
/* Close the connection. */
sqlsrv_close( $conn);
?>
My output is:
Connection established. ( ! ) Fatal error: Call to undefined function
mssql_query() in C:\Users\kians_000\dev\traka\index.php on line 42
Instead of binding try calling your procedure as a query:
mssql_query('exec SP_TPL_DeleteUser #ExternalFieldID = ' . $ExternalFieldID, $con);
I mixed together two different drivers.
There are mssql and sqlsrv drivers.
Check if the statements begin with mssql_ or sqlsrv_
I use MSSQL Express 2012 and it seems like the mssql drivers aren't used anyway.
This here works now (as a hello world):
<?php
//-----------------------------------------------
// Connect to MSSQL-DB
//-----------------------------------------------
$serverName = "KIAN-PC";
$connectionInfo = array( "Database"=>"T32Database");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false ) {
die( print_r( sqlsrv_errors(), true));
}
//-----------------------------------------------
// Perform operations with connection.
//-----------------------------------------------
if( $client_info = sqlsrv_client_info( $conn)) {
foreach( $client_info as $key => $value) {
echo $key.": ".$value."<br />";
}
} else {
echo "Error in retrieving client info.<br />";
}
/* Close the connection. */
sqlsrv_close( $conn);
?>
Thanks for everybodys help anyway!
If you're using WAMP, make sure that the mssql module is enabled. It will have a checkmark next to its name in the context menu if it is.

Categories