Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new pdo_sqlsrv tests for utf8 encoding errors #966

Merged
merged 7 commits into from
Apr 9, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_construct_attr_errors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
--TEST--
Test various connection errors with invalid attributes
--DESCRIPTION--
This is similar to sqlsrv sqlsrv_connStr.phpt such that invalid connection attributes or values used when connecting.
.phpt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed something here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was a typo... unless you have any suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just wondering if this was a typo or something else.

--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");

function invalidEncoding($binary)
{
try {
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$conn = connect("", $options);
$attr = ($binary) ? PDO::SQLSRV_ENCODING_BINARY : 'gibberish';

$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, $attr);
echo "Should have failed about an invalid encoding.\n";
} catch (PDOException $e) {
$error = '*An invalid encoding was specified for SQLSRV_ATTR_ENCODING.';
if (!fnmatch($error, $e->getMessage())) {
echo "invalidEncoding($binary)\n";
var_dump($e->getMessage());
}
}
}

function invalidServer()
{
global $uid, $pwd;

// Test an invalid server name in UTF-8
try {
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$invalid = pack("H*", "ffc0");
$conn = new PDO("sqlsrv:server = $invalid;", $uid, $pwd, $options);
echo "Should have failed to connect to invalid server.\n";
} catch (PDOException $e) {
$error1 = '*Login timeout expired';
$error2 = '*An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page*';
if (fnmatch($error1, $e->getMessage()) || fnmatch($error2, $e->getMessage())) {
; // matched at least one of the expected error messages
} else {
echo "invalidServer\n";
var_dump($e->getMessage());
}
}
}

function utf8APP()
{
global $server, $uid, $pwd;
try {
// Use a UTF-8 name
$app = pack('H*', 'c59ec6a1d0bcc49720c59bc3a4e1839dd180c580e1bb8120ce86c59ac488c4a8c4b02dc5a5e284aec397c5a7');
$dsn = "APP = $app;";
$conn = connect($dsn);
} catch (PDOException $e) {
echo "With APP in UTF8 it should not have failed!\n";
var_dump($e->getMessage());
}
}

function invalidCredentials()
{
global $server, $database;

// Use valid UTF-8
$user = pack('H*', 'c59ec6a1d0bcc49720c59bc3a4e1839dd180c580e1bb8120ce86c59ac488c4a8c4b02dc5a5e284aec397c5a7');
$passwd = pack('H*', 'c59ec6a1d0bcc49720c59bc3a4e1839dd180c580e1bb8120ce86c59ac488c4a8c4b02dc5a5e284aec397c5a7');

$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$error1 = "*Login failed for user \'*\'.";
$error2 = "*Login timeout expired*";

try {
$conn = new PDO("sqlsrv:server = $server; database = $database;", $user, $passwd, $options);
echo "Should have failed to connect\n";
} catch (PDOException $e) {
if (fnmatch($error1, $e->getMessage()) || fnmatch($error2, $e->getMessage())) {
; // matched at least one of the expected error messages
} else {
echo "invalidCredentials()\n";
var_dump($e->getMessage());
}
}
}

function invalidPassword()
{
global $server, $database;

// Use valid UTF-8
$user = pack('H*', 'c59ec6a1d0bcc49720c59bc3a4e1839dd180c580e1bb8120ce86c59ac488c4a8c4b02dc5a5e284aec397c5a7');
// Use invalid UTF-8
$passwd = pack('H*', 'c59ec6c0d0bcc49720c59bc3a4e1839dd180c580e1bb8120ce86c59ac488c4a8c4b02dc5a5e284aec397c5a7');

$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);

// Possible errors
$error = "*An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.*";
$error1 = "*Login failed for user \'*\'.";
$error2 = "*Login timeout expired*";

try {
$conn = new PDO("sqlsrv:server = $server; database = $database;", $user, $passwd, $options);
echo "Should have failed to connect\n";
} catch (PDOException $e) {
if (!fnmatch($error, $e->getMessage())) {
// Sometimes it might fail with two other possible error messages
if (fnmatch($error1, $e->getMessage()) || fnmatch($error2, $e->getMessage())) {
; // matched at least one of the expected error messages
} else {
echo "invalidPassword()\n";
var_dump($e->getMessage());
}
}
}
}

try {
invalidEncoding(false);
invalidEncoding(true);
invalidServer();
utf8APP();
invalidCredentials();
invalidPassword();

echo "Done\n";
} catch (PDOException $e) {
var_dump($e);
}
?>
--EXPECT--
Done

86 changes: 86 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_insert_fetch_invalid_utf16.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
--TEST--
Test fetching invalid UTF-16 from the server
--DESCRIPTION--
This is similar to sqlsrv 0079.phpt with checking for error conditions concerning encoding issues.
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");

try {
$conn = connect();

// The following is required or else the insertion would have failed because the input
// was invalid
$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);

// Create test table
$tableName = 'pdoUTF16invalid';
$columns = array(new ColumnMeta('int', 'id', 'identity'),
new ColumnMeta('nvarchar(100)', 'c1'));
$stmt = createTable($conn, $tableName, $columns);

// 0xdc00,0xdbff is an invalid surrogate pair
$invalidUTF16 = pack("H*", '410042004300440000DCFFDB45004600');

$insertSql = "INSERT INTO $tableName (c1) VALUES (?)";
$stmt = $conn->prepare($insertSql);
$stmt->bindParam(1, $invalidUTF16, PDO::PARAM_STR, null, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();

try {
// Now fetch data with UTF-8 encoding
$tsql = "SELECT * FROM $tableName";
$stmt = $conn->prepare($tsql);
$stmt->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8);
$stmt->execute();
$utf8 = $stmt->fetchColumn(1); // Ignore the id column
echo "fetchColumn should have failed with an error.\n";
} catch (PDOException $e) {
$error = '*An error occurred translating string for a field to UTF-8:*';
if ($e->getCode() !== "IMSSP" || !fnmatch($error, $e->getMessage())) {
var_dump($e->getMessage());
}
}

dropProc($conn, 'Utf16InvalidOut');
$createProc = <<<PROC
CREATE PROCEDURE Utf16InvalidOut
@param nvarchar(25) OUTPUT
AS
BEGIN
set @param = convert(nvarchar(25), 0x410042004300440000DCFFDB45004600);
END;
PROC;

$conn->query($createProc);

try {
$invalidUTF16Out = '';
$tsql = '{call Utf16InvalidOut(?)}';
$stmt = $conn->prepare($tsql);
$stmt->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8);
$stmt->bindParam(1, $invalidUTF16Out, PDO::PARAM_STR, 25);
$stmt->execute();
} catch (PDOException $e) {
$error = '*An error occurred translating string for an output param to UTF-8:*';
if ($e->getCode() !== "IMSSP" || !fnmatch($error, $e->getMessage())) {
var_dump($e->getMessage());
}
}

echo "Done\n";

// Done testing with the stored procedure and test table
dropProc($conn, 'Utf16InvalidOut');
dropTable($conn, $tableName);

unset($stmt);
unset($conn);
} catch (PDOException $e) {
var_dump($e->errorInfo);
}
?>
--EXPECT--
Done
106 changes: 106 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_insert_fetch_utf8stream.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
--TEST--
Test inserting UTF-8 stream via PHP including some checking of error conditions
--DESCRIPTION--
This is similar to sqlsrv 0067.phpt with checking for error conditions concerning encoding issues.
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");

try {
$conn = connect();

// Create test table
$tableName = 'pdoUTF8stream';
$columns = array(new ColumnMeta('tinyint', 'c1'),
new ColumnMeta('char(10)', 'c2'),
new ColumnMeta('float', 'c3'),
new ColumnMeta('varchar(max)', 'c4'));
$stmt = createTable($conn, $tableName, $columns);

$f1 = 1;
$f2 = "testtestte";
$f3 = 12.0;
$f4 = fopen("data://text/plain,This%20is%20some%20text%20meant%20to%20test%20binding%20parameters%20to%20streams", "r");

$insertSql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?, ?, ?, ?)";
$stmt = $conn->prepare($insertSql);
$stmt->bindParam(1, $f1);
$stmt->bindParam(2, $f2);
$stmt->bindParam(3, $f3);
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);

$stmt->execute();

// Next test UTF-8 cutoff in the middle of a valid 3 byte UTF-8 char
$utf8 = str_repeat("41", 8188);
$utf8 = $utf8 . "e38395";
$utf8 = pack("H*", $utf8);
$f4 = fopen("data://text/plain," . $utf8, "r");
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);
$stmt->execute();

// Now test a 2 byte incomplete character
$utf8 = str_repeat("41", 8188);
$utf8 = $utf8 . "dfa0";
$utf8 = pack("H*", $utf8);
$f4 = fopen("data://text/plain," . $utf8, "r");
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);
$stmt->execute();

// Then test a 4 byte incomplete character
$utf8 = str_repeat("41", 8186);
$utf8 = $utf8 . "f1a680bf";
$utf8 = pack("H*", $utf8);
$f4 = fopen("data://text/plain," . $utf8, "r");
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);
$stmt->execute();

// Finally, verify error conditions with invalid inputs
$error = '*An error occurred translating a PHP stream from UTF-8 to UTF-16:*';

// First test UTF-8 cutoff (really cutoff)
$utf8 = str_repeat("41", 8188);
$utf8 = $utf8 . "e383";
$utf8 = pack("H*", $utf8);
$f4 = fopen("data://text/plain," . $utf8, "r");
try {
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);
$stmt->execute();
echo "Should have failed with a cutoff UTF-8 string\n";
} catch (PDOException $e) {
if ($e->getCode() !== "IMSSP" || !fnmatch($error, $e->getMessage())) {
var_dump($e->getMessage());
}
}

// Then test UTF-8 invalid/corrupt stream
$utf8 = str_repeat("41", 8188);
$utf8 = $utf8 . "e38395e38395";
$utf8 = substr_replace($utf8, "fe", 1000, 2);
$utf8 = pack("H*", $utf8);
$f4 = fopen("data://text/plain," . $utf8, "r");
try {
$stmt->bindParam(4, $f4, PDO::PARAM_LOB);
$stmt->execute();
echo "Should have failed with an invalid UTF-8 string\n";
} catch (PDOException $e) {
if ($e->getCode() !== "IMSSP" || !fnmatch($error, $e->getMessage())) {
var_dump($e->getMessage());
}
}

echo "Done\n";

// Done testing with stored procedures and table
dropTable($conn, $tableName);

unset($stmt);
unset($conn);
} catch (PDOException $e) {
var_dump($e->errorInfo);
}
?>
--EXPECT--
Done
Loading