I am executing a SQL Server stored procedure that is supposed to return an output parameter (ErrCode), as well as a resultset.
I am calling the procedure from PHP using the following code, but so far have been unable to retrieve the output parameter:
$stmt = mssql_init("addFaculty", $this->db);
mssql_bind($stmt, "#FacultyID", $FacultyID, SQLCHAR);
...imagine other parameters here...
mssql_bind($stmt, "#ErrCode", &$ErrCode, SQLINT1, TRUE, FALSE, 1);
$result = mssql_execute($stmt);
echo $ErrCode
$ErrCode is always echoed as 0, even when it should return a '1' or '2'. When I execute the procedure within SQL Server Studio, however, the 'Messages' tab will correctly display a '1' or a '2'.
In doing research, I found one suggestion that stated you must use mssql_next_result() first to be able to access the output parameters. I tried this, but it simply returned a PHP
"Warning: mssql_next_result(): supplied argument is not a valid MS SQL_result resource"
I also found a reference to a similar issue in this thread but did not see a real resolution.
Like the person in that thread, I am using Linux (CentOS) with PHP5 and MS SQL Server 2005.
Does anyone have any suggestions on this? I had an issue like this in a previous project as well, and in the end, simply gave up on using output parameters (and did all my error_checking in the PHP instead) because I couldn't figure it out. It would be nice to find an answer :(
I am not a PHP guy, but I think this will help.
It says:
Note that when retrieving an output or
input/output parameter, all results
returned by the stored procedure must
be consumed before the returned
parameter value is accessible.
EDIT:
Have you tried ADODB
Check my post on this problem, I used a class extended from Zend_Db_Table_Abstract. I do not use pure PHP, still using the framework accordingly. Seens to be fine and run ok, I am even getting also the resultset back! Hope it helps:
Execute MSSQL stored procedure via Zend Framework
Related
Under certain circumstances, the built-in function in PHP called mysqli_query returns null. Such behaviour is not foreseen by the function's documentation that explains how to use it, so I tried to dive in PHP's source code itself, posted on GitHub, to see if I can figure out why sometimes mysqli_query returns null.
The queries themselves doesn't seem to be the problem: I tested the relevant SQL queries in two different ways:
Executing them manually in the MySQL Server. They work correctly.
Within a script that I created with the single purpose of testing the queries through mysqli_query(). They work under this test, and the function returns true.
However, under certain conditions, those same queries return null. The mysqli link object exists when mysqli_query function starts running, when this "returning null failure" happens.
So, looking in the PHP's GitHub repository, i found the file called mysqli_nonapi.c and, in line 556 within this file, what seems to be the built-in mysqli_query definition. Looking at the code within, it looks like it performs a basic check and, if it fails, it returns null. Here are the first lines linked above:
/* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
PHP_FUNCTION(mysqli_query){
MY_MYSQL *mysql;
zval *mysql_link;
MYSQLI_RESOURCE *mysqli_resource;
MYSQL_RES *result = NULL;
char *query = NULL;
size_t query_len;
zend_long resultmode = MYSQLI_STORE_RESULT;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
return;
}
// [...]
}
Even though I have used sometimes C code, I just know a little about C. I am aware that it uses pointers and I guess those parameters which name start with * are pointers. Anyways, I am not sure on how to interpretate this piece of code, or figuring out how it's internal flow affects PHP execution.
Long story short: I can assume somehow, the initial check shown above within the function failed for some reason. But, to find out why, I need to understand that piece of code first.
I am afraid I cannot isolate the issue to trigger the error outside production environment, which would be very useful for exhaustive testing. So, what options do I have left? Is there something I can do to debug that internal piece of code, or otherwise, figuring out why it might be failing within?
I made the tests in both PHP5 and PHP7; it fails the same way in both of them.
This is called undefined behaviour in PHP. Most instances of it have been eradicated in PHP 8, but prior to that version when you passed a wrong parameter to a built-in function, that function would usually throw a warning and return null (or false).
There were a lot of circumstances when no warning was produced at all! This behaviour was not documented on each page as this would be a mess and by definition "undefined behaviour" has no defined behaviour.
This means that code like the following would throw no warning and simply return null:
// V - string passed instead of a numerical value
var_dump(mysqli_query($mysqli, 'SELECT 1', 'foo'));
PHP was very forgiving with parameter types and when you passed the wrong type, it tried to convert it into the proper type, but when this was not possible then PHP had no defined behaviour of what should happen. Thankfully, this has been fixed in 99% of cases in PHP 8.0.
Before post this question, i searched a lot in internet but did not find anything that could solve my problem.
<?php
$result=pg_query($this->conn_link,$strSqlQuery) or die(pg_last_error());
if($result)
$data=pg_fetch_object($result);
?>
So, after execute the code above, the value of $data is false, using var_dump() function. The strange thing is that if i copy the sql string and execute directly on SGBD (Sql Manager 2007) it returning data correctly!!!
I tried use functions that return last error, but no error was shown. So, i don't have any idea why is this happening. This never happened to me.
So guys, what could be or what i could to do for try to discover this issue. Thanks!
Solved.
Be careful when use pg_query without conection parameter, it will pick up the default conection, which maybe can cause wrong conection(other database conection for example) and your query will fail.
For me, i forced a re-conection with bd before execute the query and it worked beautifully.
<?php
$bd->conect();
$result=pg_query($this->conn_link,$strSqlQuery) or die(pg_last_error());
if($result)
$data=pg_fetch_object($result);
?>
Here is the edited script without errors. And the 2 fixes applied to it. To those who helped in part, thank you. To mentions that the code is unclear or messy is inconsequential. Given that most of the following is common structure in mysql queries. Even the example documentation for mysql followed this similar flow. Members who reply should negate from pointless internet banter. Its more worth your time, and my own to do so. Those who stayed on topic and assisted, I thank you.
For example:
$row = mysqli_fetch_row(mysqli_query($con, "SELECT test_table.points FROM test_table WHERE test_table.key = '" . $key . "'"));
if ($row[0] > 0){ // exists
Where $row will return a non-zero result if true. Otherwise 0 on false. There is little need to check mysqli_fetch_row and/or mysqli_query. Since checking $row in simplicity works fine. It is unneeded to check mysqli_fetch_row and/or mysqli_query individually in a general exists condition. It does accurately provide exist / does not exist results. There is no $result $row $query just $row.
The noted deviation to that normal flow was my desire to use call_user_func. And to poll in func and params through $_GET. Will be looking more at PDO. However, the clean code before exec should do alright job for now. Which is to clean before exec.
All in all, the code works just as it should. And have since written more to manage a mysql database. From write, write chunk, read, read chunk, delete, delete chunk.
Also to collect numbered records on request. For example say you have 6 records for the same John Smith. You can now collate and scan for differences in those records. Either for what you want, dont want, etc. Or if say you just want to blindly call the first 3 of those records for John Smith.
mysqli_fetch_row & mysqli_fetch_row fix :
FROM Calling $con outside function then into as per mysql. Which in mysqli does not work as expected. There was no error with the functions, over how $con was being handled.
TO Calling $con inside function with just the added global $con. May end up using $GLOBALS even for this.
Result : Calling $con outside function then in works fine in mysql. In mysqli it requires global be set within the function. ie global $con. Or it fails.
call_user_func non-critical error fix :
FROM call_user_func($func($_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']));
TO call_user_func($func,$_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']);
Result : Both lines execute correctly. From executed with a non-critical error. TO does the same thing, but with no following non-critical error.
Sample Output for both : user=MY_Name;key=34342$ee56i1;points=1234;type=
-- code removed as fixes solved the issues --
You are using call_user_func wrong read the manutal
call_user_func first parameter is the callback - in your case it's a function inside your class so it should be something like this:
If you have a non-static function in an object:
class Test{
public function doit($a){
echo($a);
}
}
$t = new Test();
call_user_func(array($t,'doit'),'asfaasfs');
and in static functions inside object:
class Test{
public static function doit($a){
echo($a);
}
}
call_user_func('Test::doit','asfaasfs');
You have a few problems.
$con is declared outside the class, and is thus not available inside the class. You need to pass it into the class (the better option), or specify it as a global (the quick+dirty option).
mysqli_fetch_row(mysqli_query($con,'...'))
This code is obviously converted directly from your old mysql_xx() code, but it's not great.
You're ignoring any possible error condition that is returned by mysqli_query(). This means that if it fails, it'll pass false into the mysqli_fetch_row() function, which will then fail with a meaningless error expects parameter 1 to be mysqli_result, rather than actually telling you what the error was in the query.
The thing is, because of my first point above, with $con not being set, mysqli_query() is failing, and this is why you're getting the error in mysqli_fetch_row().
Ideally, you should split this code out into multiple lines. Call mysqli_query() on its own, then do some error checking, then call mysqli_fetch_row() only once you know that the query actually worked.
Hope that helps explain what the problems are here. Solve those two points, and you should be well on the way to sorting the whole thing out.
Once you've got rid of those fatal errors, you should also take time to work on the problem that your code is vulnerable to SQL injection attacks. You're currently passing your $_GET variables directly into the query strings without any sanitisation. This will make your system very fragile and easy to hack. You should consider using Parameterised Queries, which is a feature of the mysqli library designed to make it easier to deal with variables in SQL queries in a safe and secure way.
Your class is pointless at the moment, perhaps stick to writing imperative style code as it will at least be cleaner.
At the moment, you should pass $con to your MYsql class to use itself as a resource, not try to access it as a global variable.
Your are not filtering your user's input either, this is dangerous and could lead to SQL injection attacks on your site.
I'd encourage you to read through these two articles, and once you grok them, I'd also encourage you to simply switch to using PDO with prepared statements. This will stop SQL injection attacks that your code currently allows.
http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
I have a primarily Ajax-driven site, the content of which is populated by making requests to an "operator" PHP script.
While typically these requests originate in Javascript, there are occasions when it's useful to query my operator from within another PHP script.
The method I have been using is to pass a URL with query string through file_get_contents() — and then to parse the returned JSON with json_decode().
For multiple reasons, I'd like to avoid this implementation, though... I see in my error logs that the URL requests are a lot more susceptible to failure for whatever reason — and I've read that it's not very efficient.
My 1st attempt to make a generic query_operator($query_string)-type function simply require()-ed operator.php within an output buffer, captured with ob_get_contents(). I also temporarily reset the $_REQUEST array with parameters parsed from the $query_string.
This approach had too many shortcomings — problems with variable scope and the MySQL connection, specifically.
My 2nd attempt involved using the backtick operator (equivalent to shell_exec()), and mapping the $argv arguments to the $_REQUEST array.
This approach actually works very well, but on the host I'm using, the PHP (cli) version is set a 4.4.8 — and I need 5.2.x. Assuming I can't switch the (cli) version, what's the next best way to sandbox a request to another PHP script, with a query string? Any suggestions greatly appreciated.
Here's what my 2nd attempt looks like:
function query_operator($query) {
$query = '--'.str_ireplace('&', ' --', $query);
$contents = `php operator.php $query`;
if ($json = json_decode($contents, true)) {
return $json;
} else {
return $contents;
}
}
The best thing to do, in the long run, is to factor your code.
Whatever logic operator.php is doing that is needed should live in some library, which can then be used by operator.php and any other script that needs it.
When you do that, you'll avoid all the overhead of an extra PHP process, communication between two processes, and probably all your json-encoding/decoding.
If factoring is too much work to take on now, either of the strategies you describe should work as a kludge. It might be worth looking into why your make-a-loopback-http-request method (the first thing you described) caused errors. It really ought to work well, even if it's inefficient.
I am currently using SQL Server 2000 Stored Procedures with PHP. Following the PHP doc, I use mssql_bind to assign value of parameters and then execute the Stored Procedure.
The problem is that I got this bug which prevents me to bind empty strings to parameters (they are converted to NULL when the Stored Proc gets called)
I dont't want to have to convert every parameter inside the Stored Procedures to check if its NULL then convert back to an empty string. I want to be able to use empty strings as well as NULL which both have their own meaning.
Does anyone know a workaround for this in PHP ? PHP bugs website isn't very clear if that bug is fixed or when it will be fixed, I use PHP 5.2.11 (the lastest version from the 5.2 branch)
Assuming you do not want to do what you suggested, options left to you are
Download a cvs snapshot of php and install it if viable, see if it is fixed. If not viable or fixed via cvs then...
Use system() or exec() calls to use the stored procedures. If too much a hassle then...
Don't use stored procedures, do your functionality in php or other scripting code.
Alter the stored procedure to accept another value for '' strings and convert THAT to a '' string.
Do what you didn't want to do. Harsh :P But I do not see another way.
The bug #44325 proposed a patch to solve the problem, but it was not a correct solution, as it seems the problem is in ntwdblib.dll, and not in the code of the php_mssql extension.
See the comment from alexr at oplot dot com :
I'm sorry. This bug is not fixed. This
is a bug of the ntwdblib.dll. And
after latest updates the bug is
return.
When I bind a empty string, the stored
procedure received a chr(0) char
instead a empty string.
Please roll back last fixes. This bug
is irrecoverable.
Considering this, I'm not sure there's much that could be done on the PHP side :-(
Last time I worked with PHP+MSSQL on Windows, I had quite a lot of problems, like some quite similar to this one, actually ;-(
Maybe a possible solution, for you, might be to switch to the newer SQL Server Driver for PHP driver ? Note that is only works on Windows, though...
I personally don't have a MSSQL server available to test but have you tried using PDO instead of mssql directly?
PDOStatement->bindValue( mixed $parameter , mixed $value [, int $data_type ] )
bindValue()
Yes, I realize that PDO is only a wrapper but who knows, could work! :)
I have a solution that will work.
I am using ADODB (but that doesnt matter) and I have hacked the mssql driver (adodb-mssql.inc.php in the adodb5 drivers folder).
here is the code
if($var === ''){
//stupid hack to prevent mssql driver from converting empty strings to null. now they arent empty strings but they will get trimmed down to legth 0 ;-)
$var = ' ';
$type = SQLVARCHAR;
$isNull = false;
$maxLen = 0;
}
simply check if you are trying to bind an empty string and if you are change it to be non empty. it doesn't matter what value you use I just use a space.
make the type a sqlvarchar isnull should be false and now the trick is to make maxlen 0 so that the mssql driver will trim your string to an empty string.
those variables should get passsed to the mssql_bind function if that wasn't obvious.