Substring function in PHP
Beside the obvious fact that you're reinventing the wheel as this functionality is already present in php, here are some comments to your code:


Strange to use strpos() – If you want to reinvent the wheel, then I wouldn't use strpos() at all.
Doesn't restart checks – As commented upon by mdfst13, cases like ababc vs abc fails, as you don't restart the test if the first candidate fails.
Too long substrings gives index errors – Testing with octopus vs pussy results in index errors on the source string.
$a and $b are not really good names – They don't convey anything regarding their intended purpose, as $source and $substr would do.* 
No comments – It always nice to have a little comments to indicate what you are trying to achieve in a code block.


So an even more basic version which implements these comments could look like:

function isSubStr($source, $substr) {
  $len_src = strlen($source);
  $len_sub = strlen($substr);
  $max_start_pos = $len_src - $len_sub;

  // If longer, there isn't room for it
  if ($max_start_pos &lt; 0) {
    return false;
  }

  // Find start position for substring
  $pos = 0;
  while ($pos &lt;= $max_start_pos) {

    // Check if we have a valid start position
    if ($source[$pos] == $substr[0]) {

       // Assume it is a good candidate, and verify this
       $foundCandidate = true;

      // Check for equality between source and substring,
      // and verify length of both strings
      for ($subIdx = 0, $orgIdx = $pos; 
           $orgIdx &lt; $len_src &amp;&amp; $subIdx &lt; $len_sub;
           $orgIdx++, $subIdx++) {

        if ($source[$orgIdx] != $substr[$subIdx]) {
          $foundCandidate = false;
          break;
        } 
      }

      // If we exited previous loop due to exhausting the substring,
      // and not have a falsified candidate we have a match 
      if ($foundCandidate &amp;&amp; $len_sub == $subIdx) {
            return true;
      }
    }

    $pos++;
  }

  // Passed max start position without finding start of substr
  if ($pos &gt; $max_start_pos) {
    return false;
  }
}


This code passes for all of the following cases:

public function testExamples() {
      $this-&gt;assertEquals(isSubStr('cat', 'at'), true);
      $this-&gt;assertEquals(isSubStr('cat', 'fluffy'), false);
      $this-&gt;assertEquals(isSubStr('cheeze', 'ee'), true);
      $this-&gt;assertEquals(isSubStr('snow', 'o'), true);
      $this-&gt;assertEquals(isSubStr('octopus', 'top'), true);
      $this-&gt;assertEquals(isSubStr('octopus', 'zzz'), false);
      $this-&gt;assertEquals(isSubStr('octopus', 'pussy'), false);
      $this-&gt;assertEquals(isSubStr('octopus', 'tops'), false);
      $this-&gt;assertEquals(isSubStr('ababc', 'abc'), true);
      $this-&gt;assertEquals(isSubStr('abc', 'abc'), true); 
}