Bug #77853 [NEW]: Inconsistent substr_compare behaviour with empty haystack
| From: | riikka dot kalliomaki at gmail dot com | Date: | Fri, 05 Apr 2019 11:50:41 +0000 |
| Subject: | Bug #77853 [NEW]: Inconsistent substr_compare behaviour with empty haystack | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-220329@lists.php.net to get a copy of this message | ||
From: riikka dot kalliomaki at gmail dot com
Operating system:
PHP version: 7.3.4
Package: Strings related
Bug Type: Bug
Bug description:Inconsistent substr_compare behaviour with empty haystack
Description:
------------
The behavior of substr_compare is a bit odd and somewhat inconsistent,
especially when compared to other php functions.
substr_compare provides an error if the offset is *equal* or greater
than the length of the first paremeter, i.e. the haystack. Other
functions like substr() and substr_count() have no problems with offset
that are *equal* to the haystack, e.g.
substr('foo', 3) === '';
substr('foo', 4) === false;
substr_count('foo', 'o', 3) === 0;
substr_count('foo', 'o', 4) === false; // Produces PHP Warning:
substr_count(): Offset not contained in string
This creates a somewhat strange problem, that you cannot compare an
empty string with anything, e.g.
substr_compare('a', 'a', 0) === 0;
substr_compare('', '', 0) === false; // Produces PHP Warning:
substr_compare(): The start position cannot exceed initial string
length
That is, unless you set the length to 0 as well (because the internal
function short circuits 0 length comparison):
substr_compare('', '', 0, 0) === 0;
To be slightly pedantic, the manual also states the following about the
length parameter:
> The length of the comparison. The default value is the largest of the
length of the str compared to the length of main_str less the offset.
Thus, substr_compare('', '', 0, 0) should be same as
substr_compare('',
'', 0), but the short circuiting doesn't happen due to usage of default
parameter, so it causes an error.
In my opinion, this should be fixed in one of the following ways to make
a function more usable:
1. Make sure that substr_compare('', '', 0) === substr_compare('',
'',
0, 0)
2. Allow special case of offset 0, if the haystack is empty
3. Allow offset that is *equal* to the length of the haystack
The case 1 is a minimal fix to address what I consider the main "bug" or
inconsistency. The case 2 would allow some leeway that is probably a
very minimal BC break. The case 3 would make most of sense in PHP, but
is a somewhat of a BC break.
As it stands right now, general use of substr_compare is a bit unwieldy,
as you have to add additional guard clauses to check if the haystack is
empty to use the function in general case.
For example, the following function will fail with empty haystack and
nonempty needle:
function ends_with($haystack, $needle): bool {
$length = strlen($needle);
return substr_compare($haystack, $needle, -$length, $length) === 0;
}
Test script:
---------------
<?php
var_dump(substr_compare('', '', 0, 0));
var_dump(substr_compare('', '', 0));
Expected result:
----------------
int(0)
int(0)
Actual result:
--------------
int(0)
Warning: substr_compare(): The start position cannot exceed initial
string length in /Users/riikka/Source/opcodes2.php on line 4
bool(false)
--
Edit bug report at https://bugs.php.net/bug.php?id=77853&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=77853&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=77853&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=77853&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=77853&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=77853&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=77853&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=77853&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=77853&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=77853&r=support
Expected behavior: https://bugs.php.net/fix.php?id=77853&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=77853&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=77853&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=77853&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=77853&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=77853&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=77853&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=77853&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=77853&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=77853&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=77853&r=mysqlcfg