# Fastest endsWith() solution:

``````# Checks if a string ends in a string
function endsWith(\$haystack, \$needle) {
return substr(\$haystack,-strlen(\$needle))===\$needle;
}
``````

# Benchmark:

``````# This answer
function endsWith(\$haystack, \$needle) {
return substr(\$haystack,-strlen(\$needle))===\$needle;
}

function endsWith2(\$haystack, \$needle) {
\$length = strlen(\$needle);

return \$length === 0 ||
(substr(\$haystack, -\$length) === \$needle);
}

function endsWith3(\$haystack, \$needle) {
// search forward starting from end minus needle length characters
if (\$needle === '') {
return true;
}
\$diff = \strlen(\$haystack) - \strlen(\$needle);
return \$diff >= 0 && strpos(\$haystack, \$needle, \$diff) !== false;
}

function endsWith4(\$haystack, \$needle) {
return preg_match('/' . preg_quote(\$needle, '/') . '\$/', \$haystack);
}

function timedebug() {
\$test = 10000000;

\$time1 = microtime(true);
for (\$i=0; \$i < \$test; \$i++) {
\$tmp = endsWith('TestShortcode', 'Shortcode');
}
\$time2 = microtime(true);
\$result1 = \$time2 - \$time1;

for (\$i=0; \$i < \$test; \$i++) {
\$tmp = endsWith2('TestShortcode', 'Shortcode');
}
\$time3 = microtime(true);
\$result2 = \$time3 - \$time2;

for (\$i=0; \$i < \$test; \$i++) {
\$tmp = endsWith3('TestShortcode', 'Shortcode');
}
\$time4 = microtime(true);
\$result3 = \$time4 - \$time3;

for (\$i=0; \$i < \$test; \$i++) {
\$tmp = endsWith4('TestShortcode', 'Shortcode');
}
\$time5 = microtime(true);
\$result4 = \$time5 - \$time4;

echo \$test.'x endsWith: '.\$result1.' seconds # This answer<br>';
echo \$test.'x endsWith2: '.\$result4.' seconds # Accepted answer<br>';
echo \$test.'x endsWith3: '.\$result2.' seconds # Second most voted answer<br>';
echo \$test.'x endsWith4: '.\$result3.' seconds # Regex answer<br>';
exit;
}
timedebug();
``````

# Benchmark Results:

``````10000000x endsWith: 1.5760900974274 seconds # This answer
10000000x endsWith2: 3.7102129459381 seconds # Accepted answer
10000000x endsWith3: 1.8731069564819 seconds # Second most voted answer
10000000x endsWith4: 2.1521229743958 seconds # Regex answer
``````

How can I write two functions that would take a string and return if it starts with the specified character/string or ends with it?

For example:

``````\$str = '|apples}';

echo startsWith(\$str, '|'); //Returns true
echo endsWith(\$str, '}'); //Returns true
``````

All answers so far seem to do loads of unnecessary work, `strlen calculations`, `string allocations (substr)`, etc. The `'strpos'` and `'stripos'` functions return the index of the first occurrence of `\$needle` in `\$haystack`:

``````function startsWith(\$haystack,\$needle,\$case=true)
{
if (\$case)
return strpos(\$haystack, \$needle, 0) === 0;

return stripos(\$haystack, \$needle, 0) === 0;
}

function endsWith(\$haystack,\$needle,\$case=true)
{
\$expectedPosition = strlen(\$haystack) - strlen(\$needle);

if (\$case)
return strrpos(\$haystack, \$needle, 0) === \$expectedPosition;

return strripos(\$haystack, \$needle, 0) === \$expectedPosition;
}
``````

Focusing on startswith, if you are sure strings are not empty, adding a test on the first char, before the comparison, the strlen, etc., speeds things up a bit:

``````function startswith5b(\$haystack, \$needle) {
return (\$haystack{0}==\$needle{0})?strncmp(\$haystack, \$needle, strlen(\$needle)) === 0:FALSE;
}
``````

It is somehow (20%-30%) faster. Adding another char test, like \$haystack{1}===\$needle{1} does not seem to speedup things much, may even slow down.

`===` seems faster than `==` Conditional operator `(a)?b:c` seems faster than `if(a) b; else c;`

For those asking "why not use strpos?" calling other solutions "unnecessary work"

strpos is fast, but it is not the right tool for this job.

To understand, here is a little simulation as an example:

``````Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c
``````

What the computer does "inside"?

``````    With strccmp, etc...

is a===b? NO
return false

With strpos

is a===b? NO -- iterating in haysack
is a===c? NO
is a===d? NO
....
is a===g? NO
is a===g? NO
is a===a? YES
is 1===1? YES -- iterating in needle
is 2===3? YES
is 4===4? YES
....
is 8===8? YES
is c===x? NO: oh God,
is a===1? NO -- iterating in haysack again
is a===2? NO
is a===3? NO
is a===4? NO
....
is a===x? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
...
... may many times...
...
is a===b? NO
is a===a? YES -- iterating in needle again
is 1===1? YES
is 2===3? YES
is 4===4? YES
is 8===8? YES
is c===c? YES YES YES I have found the same string! yay!
was it at position 0? NOPE
What you mean NO? So the string I found is useless? YEs.
Damn.
return false
``````

Assuming strlen does not iterate the whole string (but even in that case) this is not convenient at all.

Here are two functions that don't introduce a temporary string, which could be useful when needles are substantially big:

``````function startsWith(\$haystack, \$needle)
{
return strncmp(\$haystack, \$needle, strlen(\$needle)) === 0;
}

function endsWith(\$haystack, \$needle)
{
return \$needle === '' || substr_compare(\$haystack, \$needle, -strlen(\$needle)) === 0;
}
``````

Here's a multi-byte safe version of the accepted answer, it works fine for UTF-8 strings:

``````function startsWith(\$haystack, \$needle)
{
\$length = mb_substr(\$needle, 'UTF-8');
return (mb_substr(\$haystack, 0, \$length, 'UTF-8') === \$needle);
}

function endsWith(\$haystack, \$needle)
{
\$length = mb_strlen(\$needle, 'UTF-8');
return \$length === 0 ||
(mb_substr(\$haystack, -\$length, \$length, 'UTF-8') === \$needle);
}
``````

I hope that the below answer may be efficient and also simple:

``````\$content = "The main string to search";
\$search = "T";
//For compare the begining string with case insensitive.
if(stripos(\$content, \$search) === 0) echo 'Yes';
else echo 'No';

//For compare the begining string with case sensitive.
if(strpos(\$content, \$search) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case insensitive.
if(stripos(strrev(\$content), strrev(\$search)) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case sensitive.
if(strpos(strrev(\$content), strrev(\$search)) === 0) echo 'Yes';
else echo 'No';
``````

I usually end up going with a library like underscore-php these days.

``````require_once("vendor/autoload.php"); //use if needed
use Underscore\Types\String;

\$str = "there is a string";
echo( String::startsWith(\$str, 'the') ); // 1
echo( String::endsWith(\$str, 'ring')); // 1
``````

The library is full of other handy functions.

I would do it like this

``````     function startWith(\$haystack,\$needle){
if(substr(\$haystack,0, strlen(\$needle))===\$needle)
return true;
}

function endWith(\$haystack,\$needle){
if(substr(\$haystack, -strlen(\$needle))===\$needle)
return true;
}
``````

It is possible to use `strrpos` and `strpos` to check start-with and ends-with respectively.

Note that using `strrpos` to check starts with and `strpos` to check ends with will return as soon as possible instead of checking the whole string till the end. Also, this solution does not create a temporary string. Consider explaining the reason before downvoting. Just because a f-wit at the DWTF doesn't understand how this function works or thinks there is only one solution doesn't mean this answer is wrong.

``````function startsWith(\$haystack, \$needle) {
// search backwards starting from haystack length characters from the end
return \$needle === ''
|| strrpos(\$haystack, \$needle, -strlen(\$haystack)) !== false;
}

function endsWith(\$haystack, \$needle) {
// search forward starting from end minus needle length characters
if (\$needle === '') {
return true;
}
\$diff = \strlen(\$haystack) - \strlen(\$needle);
return \$diff >= 0 && strpos(\$haystack, \$needle, \$diff) !== false;
}
``````

Tests and results (compare with this):

``````startsWith('abcdef', 'ab') -> true
startsWith('abcdef', 'cd') -> false
startsWith('abcdef', 'ef') -> false
startsWith('abcdef', '') -> true
startsWith('', 'abcdef') -> false

endsWith('abcdef', 'ab') -> false
endsWith('abcdef', 'cd') -> false
endsWith('abcdef', 'ef') -> true
endsWith('abcdef', '') -> true
endsWith('', 'abcdef') -> false
``````

Note: the `strncmp` and `substr_compare` functions will outperform this function.

Just a recommendation:

``````function startsWith(\$haystack,\$needle) {
if(\$needle==="") return true;
if(\$haystack[0]<>\$needle[0]) return false;
if(substr_compare(\$haystack,\$needle,0,strlen(\$needle))==0) return true;
return false;
}
``````

That extra line, comparing the first character of the strings, can make the false case return immediately, therefore making many of your comparisons a lot faster (7x faster when I measured). In the true case you pay virtually no price in performance for that single line so I think it's worth including. (Also, in practice, when you test many strings for a specific starting chunk, most comparisons will fail since in a typical case you're looking for something.)

Not sure why this is so difficult for people. Substr does a great job and is efficient as you don't need to search the whole string if it doesn't match.

Additionally, since I'm not checking integer values but comparing strings I don't have to necessarily have to worry about the strict === case. However, === is a good habit to get into.

``````function startsWith(\$haystack,\$needle) {
substring(\$haystack,0,strlen(\$needle)) == \$needle) { return true; }
return false;
}

function endsWith(\$haystack,\$needle) {
if(substring(\$haystack,-strlen(\$needle)) == \$needle) { return true; }
return false;
}
``````

or even better optimized.

``````function startsWith(\$haystack,\$needle) {
return substring(\$haystack,0,strlen(\$needle)) == \$needle);
}

function endsWith(\$haystack,\$needle) {
return substring(\$haystack,-strlen(\$needle)) == \$needle);
}
``````

Short and easy-to-understand one-liners without regular expressions.

startsWith() is straight forward.

``````function startsWith(\$haystack, \$needle) {
return (strpos(\$haystack, \$needle) === 0);
}
``````

endsWith() uses the slightly fancy and slow strrev():

``````function endsWith(\$haystack, \$needle) {
return (strpos(strrev(\$haystack), strrev(\$needle)) === 0);
}
``````

The answer by mpen is incredibly thorough, but, unfortunately, the provided benchmark has a very important and detrimental oversight.

Because every byte in needles and haystacks is completely random, the probability that a needle-haystack pair will differ on the very first byte is 99.609375%, which means that, on average, about 99609 of the 100000 pairs will differ on the very first byte. In other words, the benchmark is heavily biased towards `startswith` implementations which check the first byte explicitly, as `strncmp_startswith2` does.

If the test-generating loop is instead implemented as follows:

``````echo 'generating tests';
for(\$i = 0; \$i < 100000; ++\$i) {
if(\$i % 2500 === 0) echo '.';

\$haystack_length = random_int(1, 7000);
\$haystack = random_bytes(\$haystack_length);

\$needle_length = random_int(1, 3000);
\$overlap_length = min(random_int(0, \$needle_length), \$haystack_length);
\$needle = (\$needle_length > \$overlap_length) ?
substr(\$haystack, 0, \$overlap_length) . random_bytes(\$needle_length - \$overlap_length) :
substr(\$haystack, 0, \$needle_length);

\$test_cases[] = [\$haystack, \$needle];
}
echo " done!<br />";
``````

the benchmark results tell a slightly different story:

``````strncmp_startswith: 223.0 ms
substr_startswith: 228.0 ms
substr_compare_startswith: 238.0 ms
strncmp_startswith2: 253.0 ms
strpos_startswith: 349.0 ms
preg_match_startswith: 20,828.7 ms
``````

Of course, this benchmark may still not be perfectly unbiased, but it tests the efficiency of the algorithms when given partially matching needles as well.

The regex functions above, but with the other tweaks also suggested above:

`````` function startsWith(\$needle, \$haystack) {
return preg_match('/^' . preg_quote(\$needle, '/') . '/', \$haystack);
}

function endsWith(\$needle, \$haystack) {
return preg_match('/' . preg_quote(\$needle, '/') . '\$/', \$haystack);
}
``````

This question already has many answers, but in some cases you can settle for something simpler than all of them. If the string you're looking for is known (hardcoded), you can use regular expressions without any quoting etc.

Check if a string starts with 'ABC':

``````preg_match('/^ABC/', \$myString); // "^" here means beginning of string
``````

ends with 'ABC':

``````preg_match('/ABC\$/', \$myString); // "\$" here means end of string
``````

In my simple case, I wanted to check if a string ends with slash:

``````preg_match('#/\$#', \$myPath);   // Use "#" as delimiter instead of escaping slash
``````

The advantage: since it's very short and simple, you don't have to define a function (such as `endsWith()`) as shown above.

But again -- this is not a solution for every case, just this very specific one.

Updated 23-Aug-2016

# Functions

``````function substr_startswith(\$haystack, \$needle) {
return substr(\$haystack, 0, strlen(\$needle)) === \$needle;
}

function preg_match_startswith(\$haystack, \$needle) {
return preg_match('~' . preg_quote(\$needle, '~') . '~A', \$haystack) > 0;
}

function substr_compare_startswith(\$haystack, \$needle) {
return substr_compare(\$haystack, \$needle, 0, strlen(\$needle)) === 0;
}

function strpos_startswith(\$haystack, \$needle) {
return strpos(\$haystack, \$needle) === 0;
}

function strncmp_startswith(\$haystack, \$needle) {
return strncmp(\$haystack, \$needle, strlen(\$needle)) === 0;
}

function strncmp_startswith2(\$haystack, \$needle) {
return \$haystack[0] === \$needle[0]
? strncmp(\$haystack, \$needle, strlen(\$needle)) === 0
: false;
}
``````

# Tests

``````echo 'generating tests';
for(\$i = 0; \$i < 100000; ++\$i) {
if(\$i % 2500 === 0) echo '.';
\$test_cases[] = [
random_bytes(random_int(1, 7000)),
random_bytes(random_int(1, 3000)),
];
}
echo "done!\n";

\$functions = ['substr_startswith', 'preg_match_startswith', 'substr_compare_startswith', 'strpos_startswith', 'strncmp_startswith', 'strncmp_startswith2'];
\$results = [];

foreach(\$functions as \$func) {
\$start = microtime(true);
foreach(\$test_cases as \$tc) {
\$func(...\$tc);
}
\$results[\$func] = (microtime(true) - \$start) * 1000;
}

asort(\$results);

foreach(\$results as \$func => \$time) {
echo "\$func: " . number_format(\$time, 1) . " ms\n";
}
``````

# Results (PHP 7.0.9)

(Sorted fastest to slowest)

``````strncmp_startswith2: 40.2 ms
strncmp_startswith: 42.9 ms
substr_compare_startswith: 44.5 ms
substr_startswith: 48.4 ms
strpos_startswith: 138.7 ms
preg_match_startswith: 13,152.4 ms
``````

# Results (PHP 5.3.29)

(Sorted fastest to slowest)

``````strncmp_startswith2: 477.9 ms
strpos_startswith: 522.1 ms
strncmp_startswith: 617.1 ms
substr_compare_startswith: 706.7 ms
substr_startswith: 756.8 ms
preg_match_startswith: 10,200.0 ms
``````

startswith_benchmark.php

You also can use regular expressions:

``````function endsWith(\$haystack, \$needle, \$case=true) {
return preg_match("/.*{\$needle}\$/" . ((\$case) ? "" : "i"), \$haystack);
}
``````

You can use `strpos` and `strrpos`

``````\$bStartsWith = strpos(\$sHaystack, \$sNeedle) == 0;
\$bEndsWith = strrpos(\$sHaystack, \$sNeedle) == strlen(\$sHaystack)-strlen(\$sNeedle);
``````

``````\$ends_with = strrchr(\$text, '.'); // Ends with dot
\$start_with = (0 === strpos(\$text, '.')); // Starts with dot
``````

``````function startsWith(\$haystack, \$needle)
{
\$length = strlen(\$needle);
return (substr(\$haystack, 0, \$length) === \$needle);
}

function endsWith(\$haystack, \$needle)
{
\$length = strlen(\$needle);
if (\$length == 0) {
return true;
}

return (substr(\$haystack, -\$length) === \$needle);
}
``````

Use this if you don't want to use a regex.