PHP7 replace preg_replace() with preg_replace_callback()

My PHP knowledge is almost zero, my host switched to PHP7, now my online PHP script returns the following error:

preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead

Here is the piece of code which returns error:

if ($_FILES['image']['name']){
	for ($i = 0; $i < count($_FILES['image']['name']); $i++){
		$ext   = end($ext = explode('.', $_FILES['image']['name'][$i]));
		$type  = end($type = explode('/', $_FILES['image']['type'][$i]));
	$image = preg_replace('/(.*?).'.$ext.'$/ie', "totranslit('\\1')", $_FILES['image']['name'][$i]).'.'.$ext;

This piece of code is for upload of image to site.

I don’g know how to change preg_replace() to preg_replace_callback() in this context. Need the exact code.

Thanks for any help.

1 Like

Thanks for your reply. The instruction you’ve pointed out may be easy to understand for a PHP programmer, but for someone like me (zero knowledge of programming) it is very confusing.

I need help from someone to give exact code for my scenario.

I changed the following line of code:

$image = preg_replace('/(.*?).'.$ext.'$/ie', "totranslit('\\1')", $_FILES['image']['name'][$i]).'.'.$ext;

to:

		$image = preg_replace_callback(
		'/(.*?).'.$ext.'$/i',
		    function($matches){
        foreach($matches as $match){
            return totranslit($match);
        }
    }	, $_FILES['image']['name'][$i]).'.'.$ext;

Now it works but there is another problem: When I upload the image logo.jpg, its name changes to logo-jpg.jpg. Don’t know what is wrong!

$_FILES[‘image’][‘name’][$i] holds the entire filename and you are appending the extension again with the $ext.

When I remove .$ext, it does not upload any image.

Scratch the last thing.

Where is the actual upload code? It should be something like move_uploaded_file

Here is the code:

move_uploaded_file($_FILES['image']['tmp_name'][$i], $folder.'/'.$image);

Then what I said before should be the likely issue. Echo $image and see what it puts out.

The more complete portion of code is something like:

if ($_FILES['image']['name']){
	for ($i = 0; $i < count($_FILES['image']['name']); $i++){
		$ext   = end($ext = explode('.', $_FILES['image']['name'][$i]));
		$type  = end($type = explode('/', $_FILES['image']['type'][$i]));
		$image = preg_replace_callback(
		'/(.*?).'.$ext.'$/i',
		    function($matches){
        foreach($matches as $match){
            return totranslit($match);
        }
    }	, $_FILES['image']['name'][$i]).'.'.$ext;
		


		foreach ($allowed_extensions as $allow){
			if (substr($type, -strlen($allow)) == $allow){
				$allowed_upload = true;
			}
		}
		
		foreach($media_extensions as $allow){
			if(strtolower($ext) == $allow){
				$allowed_upload = true;
			}
		}

	if ($allowed_upload){ 
		if(file_exists($folder.'/'.$image) and !$overwrite){
				exit($image.' already exists.');
			}

			move_uploaded_file($_FILES['image']['tmp_name'][$i], $folder.'/'.$image);

Although there is another issue with this code, it always gives the message .already exists even if the image does not exist.

echo $image; gives logo-jpg.jpg.

I must be missing where this is defined. If it doesn’t exists prior to that if statement, then it is false, and adding not makes it true.

$overwrite is not defined anywhere prior to it.

Perhaps the overwrite is called from this portion of code:

<?php 
if($member['level'] == 1){
?> 
   <label for="overwrite"><input type="checkbox" name="overwrite" id="overwrite"><?php echo $echo['overwrite']; ?></label><br />
   <label for="thumb"><input type="checkbox" name="thumb" id="thumb" onclick="javascript:ShowOrHide('make_thumb')"<?php echo (!extension_loaded('gd') ? ' disabled' : ''); ?>><?php echo $echo['makeThumb']; ?></label><br />
   <span id="make_thumb" style="display: none;">
   <ul style="list-style-type:none">
   <li><input type="text" name="make_thumb" size="1" value="150"> <?php echo $echo['thumbSettings']; ?></li>
   <li><input type="checkbox" name="square" id="square" value="yes"><label title="<?php echo $echo['crop']; ?>" for="square"><?php echo $echo['crop']; ?></label></li>
   <li><input type="checkbox" name="shadow" id="shadow"><label title="<?php echo $echo['shadowTitle']; ?>" for="shadow"><?php echo $echo['shadow']; ?></label></li>
   </ul>
   </span>
<?php 
}
?> 

The example code at the posted to link is bogus. The matches array follows the usage for the preg_match() -

$matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.

Looping over the array is meaningless. The $matches[1] element is the filename portion that the regex pattern matches. The code for the $image = … statement should be -

		$image = preg_replace_callback(
			'/(.*?).'.$ext.'$/i',
			function($matches){
				return totranslit($matches[1]);
			}
			, $_FILES['image']['name'][$i]).'.'.$ext;

You can accomplish this without the use of the preg_ statement by simply assigning the existing exploded …[‘name’] array to a variable, popping the extension off of the end, implode, with a dot separator, what’s left back into a variable, then calling the totranslit() function on that variable.

1 Like

Thank you very much @phdr, your code solved my problem with file name. But it still displays .already exist message even if there is no image with the same name in the server.

If $image happens to be empty, the file_exists() statement ends up testing if the folder exists, which it should.

You didn’t actually post the type=‘file’ form fields. If there is a fixed number of them or you are dynamically adding them, and there’s an empty one, there won’t be an uploaded image name. Some of the possible errors will also result in an empty image name. In fact, the code needs to test the [‘error’] element and only process the uploaded files if there is no upload error.

The code should also set up user error messages for those things that the user did that he/she can correct - not uploading a ‘required’ file, file size too large or too small, allowed mime type, allowed extension.

Next, using the mime type from the upload is not safe as the value can be set to anything. You should determine the mime type on the server.

Lastly, when uploading files (any post method form submission), the size of the submitted post data can exceed the post_max_size setting. When this occurs, both the $_POST and $_FILES arrays will be empty and your code needs to detect this condition before trying to reference any of the submitted form data.

Dear @phdr, please help me with this piece of code too. I need to change peg_replace() to preg_replace_callback() in these lines too:

function category_get_tree($prefix = '', $tpl = '{name}', $no_prefix = true, $id = 0, $level = 0){
global $sql, $PHP_SELF;
static $johnny_left_teat;

	$level++;

	foreach ($sql->select(array('table' => 'categories', 'where' => array("parent = $id"), 'orderby' => array('id', 'ASC'))) as $row){
		$find = array('/{id}/i', '/{name}/i', '/{url}/i', '/{icon}/i', '/{template}/i', '/{prefix}/i', '/\[php\](.*?)\[\/php\]/ie');
		$repl = array($row['id'], $row['name'], $row['url'], ($row['icon'] ? '<img src="'.$row['icon'].'" alt="'.$row['name'].'" border="0" align="absmiddle">' : ''), $row['template'], (($row['parent'] or !$no_prefix) ? $prefix : ''), '\\1');
		$johnny_left_teat .= ($no_prefix ? preg_replace('/('.$prefix.'{1})$/i', '', str_repeat($prefix, $level)) : str_repeat($prefix, $level));
		$johnny_left_teat .= preg_replace($find, $repl, $tpl);
		category_get_tree($prefix, $tpl, $no_prefix, $row['id'], $level);
	}
return $johnny_left_teat;
}

Because there’s an array of patterns and replacements, only one of which is using the /e modifier, you would actually use preg_replace_callback_array(), see this fairly recent reply - Convert preg_replace to preg_replace_callback with array inputs

If you need additional help with this new problem, you should start a new thread for it.

1 Like

I need to change peg_replace() to preg_replace_callback() in these lines:

function category_get_tree($prefix = '', $tpl = '{name}', $no_prefix = true, $id = 0, $level = 0){
global $sql, $PHP_SELF;
static $johnny_left_teat;

	$level++;

	foreach ($sql->select(array('table' => 'categories', 'where' => array("parent = $id"), 'orderby' => array('id', 'ASC'))) as $row){
		$find = array('/{id}/i', '/{name}/i', '/{url}/i', '/{icon}/i', '/{template}/i', '/{prefix}/i', '/\[php\](.*?)\[\/php\]/ie');
		$repl = array($row['id'], $row['name'], $row['url'], ($row['icon'] ? '<img src="'.$row['icon'].'" alt="'.$row['name'].'" border="0" align="absmiddle">' : ''), $row['template'], (($row['parent'] or !$no_prefix) ? $prefix : ''), '\\1');
		$johnny_left_teat .= ($no_prefix ? preg_replace('/('.$prefix.'{1})$/i', '', str_repeat($prefix, $level)) : str_repeat($prefix, $level));
		$johnny_left_teat .= preg_replace($find, $repl, $tpl);
		category_get_tree($prefix, $tpl, $no_prefix, $row['id'], $level);
	}
return $johnny_left_teat;
}

I receive the following error when run the above code:

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in X:\xampp\....\functions.inc.php on line 726

Kindly help me with the code since I have no PHP coding knowledge.

Sponsor our Newsletter | Privacy Policy | Terms of Service