Strpos error parsing php

I’m using a function to replace tags with php code in a script that generates html and replaces tags with pre-set content but I’m getting the error
"Offset not contained in string… on line 424 "

Which is the following line in this function: while(strpos($page, “[[”, $pos) !== false)

function parsePHPTag($page)
{
	global $PHP_TAG;
	$pos = 0;
	while(strpos($page, "[[", $pos) !== false)
	{
		$pos = strpos($page, "[[", $pos);
		$end_pos = strpos($page, "]]", $pos + 1);
		
		$tag = substr($page, $pos, $end_pos - $pos + 2);
		
		if(array_key_exists($tag, $PHP_TAG))
		{
			$ch = curl_init(); 
			
			curl_setopt ($ch, CURLOPT_URL, PHP_TEMP_URL. $PHP_TAG[$tag]); 
			curl_setopt ($ch, CURLOPT_HEADER, 0); 
			
			ob_start();
			curl_exec ($ch); 
			$content = ob_get_contents();
			ob_end_clean();
			
			$page = str_replace($tag, $content, $page);
		}
		
		$pos++;
	}
	return $page;
}

This used to work, but there have been a few php version changes (like from 3.whatever to 5.whatever since the last time I’ve used this script. I’ll clean up the global crap after I figure out (with a little help) why i’m kicking up this error.

I sounds like $page is empty therefor the offset at position 0 doesn’t exist.

So, just so we’re clear, you’re getting the content of the tag from this ‘webservice’ and $page contains the page template?

I’m passing a value there - can even echo it out before I call the function so it exists. That’s what I thought at first, then since I know I’m sending a page I figured it was something else that’s changed.

Read through the docs for strpos and don’t see anything I’m doing wrong - baffled really.

Try this.


<?php
function parsePHPTag($page){
  
  global $PHP_TAG;
  
  $tags = array();
  preg_match_all('~\\[\\[([^\\]]+)\\]\\]~', $page, $tags);
  $tags = isset($tags[1]) ? $tags[1] : array();

  foreach($tags as $tag){
    
    if(false === array_key_exists($tag, $PHP_TAG){
      continue;
    }
    
    $ch = curl_init();
    
    curl_setopt_array(
      $ch,
      array(
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_URL             => PHP_TEMP_URL . $PHP_TAG[$tag]
      )
    )
    
    $response = curl_exec($ch);
    
    $page = str_replace(sprintf('[[%s]]', $tag), $response, $page);
    
  }
  
  return $page;
}

Yes,

I’m pulling the contents from a file on the server, and I’m passing $page as a valid value that I can echo out.

I can also echo out $PHP_TAG[$tag] and it’s correct in the function.

The problem will occur if a tag occurs at the end of the $page string and is replaced by an empty string (i.e., $content is empty).

This is because, if you take the value of $pos at the time the last tag replacement occurs this is equal to the length of the subject string minus the length of the tag. If the tag is replaced by nothing, then $pos is at the very end of the string. Then $pos is incremented by one ($pos++) which takes the position beyond the end of this new string. Hopefully that makes sense. (:

Few errors thrown up and I had to add some ) and ;. Corrected code:

function parsePHPTag($page){
  
  global $PHP_TAG;
  
  $tags = array();
  preg_match_all('~\\[\\[([^\\]]+)\\]\\]~', $page, $tags);
  $tags = isset($tags[1]) ? $tags[1] : array();

  foreach($tags as $tag){
    
    if(false == array_key_exists($tag, $PHP_TAG)){
      continue;
    }
    
    $ch = curl_init();
    
    curl_setopt_array(
      $ch,
      array(
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_URL             => PHP_TEMP_URL . $PHP_TAG[$tag]
      )
    );
    
    $response = curl_exec($ch);
    
    $page = str_replace(sprintf('[[%s]]', $tag), $response, $page);
    
  }
  
  return $page;
}

Now I’m not actually replacing anything - the tag remains. $PHP_TAG[$tag] is empty when I echo it out… (wasn’t empty in previous code). Tags are structured like this: [[iamtag]] so I’m not sure if that regex is right as well. At least I’ve got a starting point - so thank you. If you see something jumping out at you, i’d love any pointers.

Well it won’t replace anything if $PHP_TAG[$tag] is empty. I’m going to make an uneducated guess and assume $PHP_TAG has the full tag as the array key? I.e. [[name]] ?

If so, try this then.


<?php
function parsePHPTag($page){
  
  global $PHP_TAG;
  
  $tags = array();
  preg_match_all('~\\[\\[([^\\]]+)\\]\\]~', $page, $tags);
  $tags = isset($tags[1]) ? $tags[1] : array() ;

  foreach($tags as $tag){
    
    $tag = sprintf('[[%s]]', $tag);
    
    if(false === array_key_exists($tag, $PHP_TAG)){
      continue;
    }
    
    $ch = curl_init();
    
    curl_setopt_array(
      $ch,
      array(
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_URL             => PHP_TEMP_URL . $PHP_TAG[$tag]
      )
    );
    
    $response = curl_exec($ch);
    
    $page = str_replace($tag, $response, $page);
    
  }
  
  return $page;
}

:slight_smile:

Anthony - you are awesome. That takes care of it - and I can certainly handle the rest.

You’re matching the bracketed tags with the regex, so why not use those rather than extract the innards of the tag then re-wrap in brackets?

E.g.


  preg_match_all('~\\[\\[[^\\]]+\\]\\]~', $page, $tags);
  foreach($tags[0] as $tag){

Off Topic:

It would likely be much more efficient to use cURL multi to make the requests in parallel rather than in sequence as they are now; if you’d entertain going down that route.

You’re right, that makes much more sense. Personally, I’d prefer to see the ‘tag web service’ accept a collection of tags rather one at a time.