php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #9369 Bug in foreach, reference (See Bug ID#9365, too)
Submitted: 2001-02-21 08:09 UTC Modified: 2001-04-20 09:27 UTC
From: yohgaki at dd dot iij4u dot or dot jp Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 4.0.4pl1 OS: RedHat Linux7/j
Private report: No CVE-ID: None
 [2001-02-21 08:09 UTC] yohgaki at dd dot iij4u dot or dot jp
I found other strange behaviors with much more simple scripts. It is very similar to what I experienced, but it differ a little. Bug ID#9365 
(I got default HTML for null output. i.e. output that 
== FILE START ==
<?php 
?>
== FILE END ==
 script shows. These scripts do not show that.)

Here is 3 php files. (It does not have to be 3 files, but I've test with these 3 files)
- test.php (just a submission handler. Defines some functions)
- test2.php (File to be executed, when user hit submit button. Defines some functions)
- test3.php (Submit form)

Test result is written in test2.php. Please refer the comments in test2.php (Test result is a little differ when I use multi-byte char code)

I've fund this, since I have very similar mistake in my code when I get rid of function - refer to 1st post what I mean (Bug ID#9365) There was a variable name collision, which I didn't care at all at that time. I passed EUC char code string where I should pass multi-dimensional array. Fixing this solved 2nd behavior. (Note: I still couldn't get the same behavior with these simple scripts. Fixing this bug may fix it, too.)  

Some of them are bug for sure, some error message is misleading, some might be inevitable due to PHP's reference implementation. Some might be already reported as bug/misbehavior. 

I'll try to find out when PHP stops and restart script execution from the beginning. This would be much more difficult, since the code does not have obvious mistake like this one. Or is this reported as bug already? If so, please let me know.

== test.php ==
<?php
if (isset($HTTP_POST_VARS['sub_btn'])) {
 include('test2.php');
 exit;
}
else {
 include('test3.php');
 exit;
}

function pmsg(&$msg) {
 foreach ($msg[1] as $v) {
  print("<div class=\"error\">$v</div>\n");
 }
 foreach ($msg[0] as $v) {
  print("<div class=\"message\">$v</div>\n");
 }
}

function pmsg2(&$msg) {
 while (list($k,$v) = each($msg[1])) {
  print("<div class=\"error\">$v</div>\n");
 }
 while (list($k,$v) = each($msg[0])) {
  print("<div class=\"message\">$v</div>\n");
 }
}
?>
=== END test.php ===

=== test2.php ===
<html>
<head>
</head>
<body>
THIS IS TEST2.PHP<br>
<?php 
// NOTE: error report level is E_ALL

$msg = 'abcd';
$msg2 = '????????????????????'; // multi-byte EUC char code
$msg3 = "????????????????????"; // multi-byte EUC char code
//pmsg($msg1);   // <= PHP does NOT (cannot?) complains illegal pass by reference at all. 
// With $msg, IE5.5 complains "Can't find server or DNS error"
// With $msg2 or $msg3, IE5.5 just spins. It seems waiting server response. Stop button seems does not stop operation.
// Warning: Invalid argument supplied for foreach() in .../tmp/test.php on line 12 (for unintialized var). Should complain for use of undefined var when it used.


//pmsg2($msg);  // <= PHP complains "only variable can be passed by reference" as expected.
    // The same result for $msg, $msg2, $msg3
// Fatal error: Only variables can be passed by reference in .../tmp/test.php on line 21 ($msg,$msg2,$msg3)
// Warning: Variable passed to each() is not an array or object in .../tmp/test.php on line 21 (for uninitialized var) Should complain for use of undefined var when it used.


//pmsg3($msg);  // <= PHP does NOT (cannot?) complains at all like pmsg()
// With $msg IE5.5 just spins. It seems waiting server response.  Stop button seems does not stop operation.
// With $msg2 or $msg3, IE5.5 complains "Can't find server or DNS error"
// Warning: Invalid argument supplied for foreach() in ../tmp/test2.php on line xx <- complained at inside pmsg3() (for uninitialized var) Should complain for use of undefined var when it used.
// Note: behavior is differ from pmsg()!


//pmsg4($msg);   // <= PHP complains
// Fatal error: Only variables can be passed by reference in .../tmp/test2.php on line xx ($msg,$msg2,$msg3)
// Warning: Variable passed to each() is not an array or object in .../tmp/test2.php on line xx <- complained at inside pmsg4() (for uninitialized var) Should complain for use of undefined var when it used.


pmsg5($msg3);  // PHP does not (cannot?) complain?
// With $msg IE5.5 just spins. It seems waiting server response.  Stop button seems does not stop operation.
// With $msg2 IE5.5 complains "Can't find server or DNS error"
// With $msg3 IE5.5 just spins. It seems waiting server response.  Stop button seems does not stop operation.
// PHP show expected error messages for undefined var.
// Note: See the difference with pmsg6().


//pmsg6($msg3);  // PHP shows acceptable error messages for passing string where it should be array.
// Fatal error: Only variables can be passed by reference in .../tmp/test2.php on line xx <- complained at inside pmsg5 ($msg,$msg2,$msg3);
// Warning: Undefined variable: msg1 in .../tmp/test2.php on line xx (Undefined var) OK
// Warning: Variable passed to each() is not an array or object in .../tmp/test2.php on line xx (Undefined var) OK


function pmsg3(&$msg) {
 foreach ($msg[1] as $v) {
  print("<div class=\"error\">$v</div>\n");
 }
 foreach ($msg[0] as $v) {
  print("<div class=\"message\">$v</div>\n");
 }
}


function pmsg4(&$msg) {
 while (list($k,$v) = each($msg[1])) {
  print("<div class=\"error\">$v</div>\n");
 }
 while (list($k,$v) = each($msg[0])) {
  print("<div class=\"message\">$v</div>\n");
 }
}


function pmsg5($msg) {
 foreach ($msg[1] as $v) {
  print("<div class=\"error\">$v</div>\n");
 }
 foreach ($msg[0] as $v) {
  print("<div class=\"message\">$v</div>\n");
 }
}


function pmsg6($msg) {
 while (list($k,$v) = each($msg[1])) {
  print("<div class=\"error\">$v</div>\n");
 }
 while (list($k,$v) = each($msg[0])) {
  print("<div class=\"message\">$v</div>\n");
 }
}

?>
END<br>
</body>
</html>
=== END test2.php ===

=== test3.php ===
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
</head>

<body bgcolor="#FFFFFF">
<p>THIS IS TEST3.PHP </p>
<form name="form1" method="post">
<input type="submit" name="sub_btn" value="send">
<input type="text" name="textfield">
</form>
<p>END</p>
</body>
</html>
=== END test3.php ===


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-03-16 22:08 UTC] yohgaki at dd dot iij4u dot or dot jp
After I upgraded my test machine's glibc and gcc, I didn't check if this bug is happen on my machine. Unfortunately it still exists. (Upgrading glibc fixed malformed man pages when EUC-JP is used, though)

I wrote a new test code for developers so that you can easily verify this bug. (Single php file with HTML form to play with this errata)

Note: First of all, programmers should NOT write this kind of code. i.e. Using scalar where array is expected, this is error anyway. 

Try test case "foreach and value" and "foreach and reference". PHP does not complain illegal use of variable at all, but empty outputs.

This PHP behavior is not acceptable for many users I think. Since if programmer write PHP code,  that does this kind of illegal use of variables, can be very hard to find.

I also interested in why PHP behave differently when ASCII is used for scalar and when EUC-JP (Multi-byte Charset) is used for scalar.

======== source code =======
<html>
<head>
<title>Foreach and Reference Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
</head>

<body bgcolor="#FFFFFF">
<h1>Foreach and Reference Bug Test Page</h1>
<h3>Test Function: <?php isset($HTTP_POST_VARS['action']) ? print($HTTP_POST_VARS['action']) : print('Function is not set'); ?></h3>
<h3>Test Param: <?php isset($HTTP_POST_VARS['test_mode']) ? print($HTTP_POST_VARS['test_mode']) : print('Mode is not set'); ?></h3>
<form name="form1" method="post" >
<input type="submit" name="Submit" value="while and value">
<input type="hidden" name="action" value="while_and_value">
<input type="radio" name="test_mode" value="ascii" checked>
ASCII Text Scalar 
<input type="radio" name="test_mode" value="euc_jp">
EUC-JP Text Scalar 
</form>
<form name="form2" method="post" >
<input type="submit" name="Submit2" value="while and reference">
<input type="hidden" name="action" value="while_and_reference">
<input type="radio" name="test_mode" value="ascii" checked>
ASCII Text Scalar 
<input type="radio" name="test_mode" value="euc_jp">
EUC-JP Text Scalar 
</form>
<h3>?@</h3>
<form name="form3" method="post" >
<input type="submit" name="Submit3" value="foreach and value">
<input type="hidden" name="action" value="foreach_and_value">
<input type="radio" name="test_mode" value="ascii" checked>
ASCII Text Scalar 
<input type="radio" name="test_mode" value="euc_jp">
EUC-JP Text Scalar 
</form>
<form name="form4" method="post" >
<input type="submit" name="Submit22" value="foreach and reference">
<input type="hidden" name="action" value="foreach_and_reference">
<input type="radio" name="test_mode" value="ascii" checked>
ASCII Text Scalar 
<input type="radio" name="test_mode" value="euc_jp">
EUC-JP Text Scalar 
</form>
<?php 
// NOTE: error report level is E_ALL

$ascii	= 'abcdefghijklmn';			// plain ascii
$euc_jp = '????????????????????';	// multi-byte EUC char code

function while_and_value($msg) {
 while (list($k,$v) = each($msg[1])) {
  print($v);
 }
 while (list($k,$v) = each($msg[0])) {
  print($v);
 }
}

function while_and_reference(&$msg) {
 while (list($k,$v) = each($msg[1])) {
  print($v);
 }
 while (list($k,$v) = each($msg[0])) {
  print($v);
 }
}

function foreach_and_value($msg) {
 foreach ($msg[1] as $v) {
  print($v);
 }
 foreach ($msg[0] as $v) {
  print($v);
 }
}

function foreach_and_reference(&$msg) {
 foreach ($msg[1] as $v) {
  print($v);
 }
 foreach ($msg[0] as $v) {
  print($v);
 }
}


// Call function specified with $action with a paramter specified with $test_mode
if (isset($HTTP_POST_VARS['action'])) {
	$test_mode = $HTTP_POST_VARS['test_mode']; // ascii or euc_jp

	$action = $HTTP_POST_VARS['action']; // One of 4 function
	$action($$test_mode); 
}
?>
</body>
</html>

 [2001-04-05 21:39 UTC] yohgaki at dd dot iij4u dot or dot jp
I've tested against 
  - PHP4.0.5RC1 Windows/Apache SAPI
  - PHP4.0.5RC6 Linux/Apache SAPI

It's still there.

I think this bug is better to be fixed soon, even if this is a programmer's error. For example, if user change HTML form values from array to sclar and forgot to change PHP code, programmers are crueless what's wrong. If PHP could issue warning, it would be easy to find problem.

Please let me know if you don't have this problem.

FYI:
Very simpile code like follows PHP works as it should be (Warning message is displyed), but not for longer code. ('server not found or dns error' or empty page. Try code that I've submitted. The later one is self contained single file.)

<?php
$str = 'AAAAAAAAAAAAA';

// This works (raise warning message)
foreach ($str as $v => $k) {
}
?>

 [2001-04-20 09:27 UTC] andi@php.net
Fixed in CVS. Thanks for the report.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Apr 20 11:01:27 2024 UTC