php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #24463 SQL Server Query + Redirect = 502 Error
Submitted: 2003-07-02 13:19 UTC Modified: 2017-09-20 14:18 UTC
Votes:2
Avg. Score:4.5 ± 0.5
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: nospam at kolbly dot com Assigned: cmb (profile)
Status: Closed Package: ODBC related
PHP Version: 4.3.2 OS: Win2003 Server
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: nospam at kolbly dot com
New email:
PHP Version: OS:

 

 [2003-07-02 13:19 UTC] nospam at kolbly dot com
Description:
------------
When redirecting to a .php page that connects to an SQL Server database via ODBC, IIS produces a 502 error intermittently on slower machines and 100% on faster machines.

This is admittedly a duplicate of Bug #9852 (Which is currently closed),  but my tests have pointed that the problem is with PHP, not IIS.  

I have opened up an Incident with Microsoft and we are at the point where if I can reproduce the bug using some non-php code, they will duplicate my setup exactly in their lab and have their developers tackle it.  But, so far I cannot reproduce the error with any non-php code.  I traced the php function calls, and wrote a C program that calls the exact same odbc calls as php, but this does NOT break IIS.  I can only conclude that the issue is within PHP or Zend or at the very least it is still very much in doubt as to which code is at fault here.

I have tried ALL the suggested workarounds from Bug #9852 with no luck.  I will be forced to rewrite 8 websites in .asp or .net if I can?t fix this.   

If anybody has a way to reproduce this error using C/C++/C#/ASP or some other ?Microsoft-Approved? language, please send me your source code. (nospam@kolbly.com)


Reproduce code:
---------------
<?php
$dbconn = odbc_connect("bug", "buguser", "bugpass");
$rs = odbc_exec($dbconn, "select * from employees");
while(odbc_fetch_row($rs)) {
	$EmployeeID = odbc_result($rs, "EmployeeID");
}
if (isset($_POST['Submit'])) {
	header("Location: test1a.php"); die;
}
?>
<html>
<head>
<title>Bug Test</title>
<meta http-equiv="Content-Type" content="text/plain; charset=iso-8859-1">
</head>
<body>
<form name="form1" method="post" action="test1a.php">
<p>Click Submit to post back to this page.</p>
<input type="submit" name="Submit" value="Submit">
</form>
</body>
</html>

Expected result:
----------------
Click Submit to post back to this page.

[Submit]

Actual result:
--------------
CGI Error
The specified CGI application misbehaved by not returning a complete set of HTTP headers.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-07-08 15:01 UTC] nospam at kolbly dot com
An update and some additional comments :

I have been able to suck out odbc calls from the php source php_odbc.c and been able to recreate the problem using code I'll post to the end of this message.

I've successfully opened up a case w/Microsoft and they're in the process of recreating the problem in their labs.  I'll post their results here.

One note : php_odbc.c has many calls that are deprecated by Microsoft.  This may or may not be a contributing factor.  I've been able to successfully eliminate the problem on my test platform by adding a Sleep(1) at the end of each of the following functions in php_odbc.c - SQLFreeStmt(), SQLDisconnect(), SQLFreeConnect(), and SQLFreeEnv().  

Unrelated side note to PHP developers: When PHP is compiled with Cygwin utils instead of the win32build\bin utils, then php.ini ALWAYS has a parsing problem at the last line.  An update to the windows install doc would likely save many a developer some frustration.  


breakiis.c .....

#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdlib.h>

#include <time.h>
#include <stdio.h>

#define MYSQLSUCCESS(rc) ((rc==SQL_SUCCESS)||(rc==SQL_SUCCESS_WITH_INFO))
#define MAX_NAMES	100
#define MAX_NAME_SIZE 25

#define DSN	"bug"					// ODBC System Data Source, points to Northwind DB
#define DB_USER "buguser"		// Database user with privileges on Northwind DB
#define DB_PASS "bugpass"		// Database password

#define LOGFILE "d:\\weblogs\\mydebug.log"

void single_page_load();
void auto_reload_page();
void get_data_using_odbc(int *count, char names[][MAX_NAME_SIZE]);

void mydebug(const char *msg);

/**
 ****************************************************************************
 * main()
 *
 * Try to break IIS using native ODBC funcs
 ****************************************************************************
 */
int main(int argc, char* argv[])
{
	mydebug("main() start...");

	auto_reload_page();

	mydebug("main() end...");

	return 0;
}


/**
 ****************************************************************************
 * get_data_using_odbc()
 *
 * Connect to the SQL Server 2000 Database Northwind
 * Setup an ODBC DataSource named DSN, a Database user DB_USER, and 
 * password DB_PASS.
 ****************************************************************************
 */
void get_data_using_odbc(int *count, char names[][MAX_NAME_SIZE])
{
   RETCODE rc;						// ODBC return code
   HENV henv;						// Environment   
   HDBC hdbc;						// Connection handle
   HSTMT hstmt;					// Statement handle
   unsigned char szData[100];	// Returned data storage
   SDWORD cbData;					// Output length of data
	int index = 0;
	DWORD zzz = 1;					// Sleep period - Set to 1 to aleviate problem

	mydebug("get_data_using_odbc() start...");


	// Connect Up
   SQLAllocEnv(&henv);
   SQLAllocConnect(henv,&hdbc);

   rc = SQLConnect(hdbc, (SQLCHAR *)DSN, SQL_NTS, (SQLCHAR *)DB_USER, SQL_NTS, (SQLCHAR *)DB_PASS, SQL_NTS);
   
	// Exec Stmt
   rc = SQLAllocStmt(hdbc,&hstmt);
  
	rc = SQLExecDirect(hstmt, (SQLCHAR *)"SELECT FirstName FROM employees", SQL_NTS);

	for (rc = SQLFetch(hstmt); (rc == SQL_SUCCESS) && (index < MAX_NAMES); rc=SQLFetch(hstmt))
   {
		SQLGetData(hstmt, 1, SQL_C_CHAR, szData, sizeof(szData), &cbData);
		sprintf(names[index], "%s", (const char *) szData);
		index++;
   }
	*count = index;

   SQLFreeStmt(hstmt, SQL_DROP);
		//Sleep(zzz);

   rc = SQLDisconnect(hdbc);
		//Sleep(zzz);

   rc = SQLFreeConnect(hdbc);
		//Sleep(zzz);

	rc = SQLFreeEnv(henv);
		//Sleep(zzz);

	mydebug("get_data_using_odbc() end...");

}// get_data_using_odbc()


/**
 ****************************************************************************
 * auto_reload_page()
 *
 * Have the web page keep reloading itself while incrementing a counter
 ****************************************************************************
*/
void auto_reload_page()
{
	char *data;
	double count;

	int i;
	char names[MAX_NAMES][MAX_NAME_SIZE];
	int num = 0;

	mydebug("auto_reload_page() start...");

	ZeroMemory(names, sizeof(names));

	// Comment out below and this page reloads just fine
	get_data_using_odbc(&num, names);

	data = getenv("QUERY_STRING");
	if(data == NULL) 
		count=1;
	else
		count = atof(data);

	printf("content-type: text/html\n\n");

	printf("<html>");
	printf("<head>");
	printf("<title>BreakIIS</title>");
	printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">");
	printf("</head>");
	printf("<body>");
	printf("Loading page with value %5f<br><br>\n", count);
	count++;

	for (i = 0; i < num; i++) {
		printf("%s<br>\n", names[i]);
	}

	printf("<script>location.href='breakiis.exe?%f'</script>", count);

	printf("</body>");
	printf("</html>");
	
	mydebug("auto_reload_page() end...");

}// auto_reload_page()


/**
 ****************************************************************************
 * void single_page_load()
 *
 * Have the web page keep reloading itself once the user presses "submit"
 ****************************************************************************
*/
void single_page_load()
{
	int i;
	char names[MAX_NAMES][MAX_NAME_SIZE];
	int num = 0;

	ZeroMemory(names, sizeof(names));

	get_data_using_odbc(&num, names);

	printf("content-type: text/html\n\n");

	printf("<html>");
	printf("<head>");
	printf("<title>BreakIIS</title>");
	printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">");
	printf("</head>");
	printf("<body>");

	for (i = 0; i < num; i++) {
		printf("%s<br>\n", names[i]);
	}

	printf("<form name=\"form1\" method=\"post\" action=\"breakiis.exe\">");
	printf("<p>Click Submit to post back to this page.</p>");
	printf("<input type=\"submit\" name=\"Submit\" value=\"Submit\">");
	printf("</form>");

	printf("</body>");
	printf("</html>");

}// single_page_load()

/**
 ****************************************************************************
 * mydebug()
 *
 * Simply write a logfile to LOGFILE
 ****************************************************************************
 */
void mydebug(const char *msg)
{

	char datetime[120];
	FILE *f;
	time_t curtime;
	struct tm *loctime;

	ZeroMemory(datetime, sizeof(datetime));

	curtime = time(NULL);
	loctime = localtime(&curtime);
	strftime(datetime, 119, "%Y-%m-%d %H:%M:%S", loctime);

	f = fopen(LOGFILE, "a");
	if (f) {
		fprintf(f, "%s : %s\n", datetime, msg);
		fclose(f);
	}

}// mydebug()
 [2003-07-08 15:19 UTC] kalowsky@php.net
As for the ODBC code, yes it is all based on ODBC v2, a large percentage of which has been depricated.  There is movement to udpate this, but ODBC spec REQUIRES that there be backwards compatiblity options with newer spec drivers.  I don't believe that is the issue at all.  Not sure if this should be marked as IIS or ODBC related...
 [2003-08-05 13:50 UTC] nospam at kolbly dot com
Some progress is being made on Microsoft's end and we seem to have a viable working workaround now that does NOT involve slowing down page redirects.  This appears to work under both Win2000 and Win2003.  

When IIS spits out a 502 error, it appears that our CGI exe does not even get loaded.  When IIS first loads up the CGI exe - it appears to fail during a Loadlibrary() call.  Which library fails to load is still undetermined because so far when any debuggers are attached to the IIS process, the problem cannot be reproduced.  The best working theory at this point is that some ODBC code is setting up a very fast global lock that IIS can subsequently run into later on if the next call is fast enough.  The workaround involves running the CGI as the "system" account instead of a "user" account by changing a setting in the IIS metabase.  The system account apparently does not have a problem with our potential global locks not releasing.

To change the IIS metabase setting, create a VBS file called fixiis.vbs and paste the following code there :
dim oIISObj 
Set oIISObj = GetObject("IIS://localhost/W3SVC/1/Root") 
oIISObj.CreateProcessAsUser = False 
oIISObj.SetInfo 
Set oIISObj = nothing

So far this has "Fixed" my problem on every configuration I've tried.  If you want to do this, please do consider the security considerations of running your PHP code under the system account
 [2005-01-28 09:08 UTC] jconnolly at eedo dot com
i WROTE breakiis.c. i noticed the stolen code in that breakiis example, ha ha ha, nice though, mine was specifically designed to be basic but i noticed the cout stuff is my code exactly, anways, YES, i'm gonna marry a carrot,.... ohhh, she admitted it, she's gonna marry a carrot...

Jeff Connolly

jconnolly@eedo.com
 [2016-12-30 18:48 UTC] cmb@php.net
-Package: Feature/Change Request +Package: ODBC related
 [2017-09-20 14:18 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2017-09-20 14:18 UTC] cmb@php.net
> As for the ODBC code, yes it is all based on ODBC v2, […]

This has changed in the meantime, so I'm closing this ticket.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 21:01:36 2024 UTC