EDIT - I have completely re-written the logic below but I'm sure it can still be improved.
EDIT - The current working code for the alternate theme selector is at GitHub. I'd still like to improve on it but it's a lot cleaner than what I started with. At this point, I'll take the issue thread there since user testing will reveal the next steps.
New Logic:
<?php
// Fetch theme options array
global $ats_plugin;
global $is_IE;
// Initialize the main variables
$ats_active = 0;
$the_theme = null;
// We only want to run this fat chunk of logic on IE since it's IE with the issues
if ( $is_IE ) {
// Is a supported useragent active?
function checkActive($data) {
global $ats_active;
$user_agent = $_SERVER['HTTP_USER_AGENT'];
switch($user_agent) {
case strpos($user_agent, 'MSIE 5') :
if ($data['ie5_switch'] == 1 && !empty($data['ie5_theme'])) {
$ats_active = 'ie5';
};
break;
case strpos($user_agent, 'MSIE 6') :
if ($data['ie6_switch'] == 1 && !empty($data['ie6_theme'])) {
$ats_active = 'ie6';
};
break;
case strpos($user_agent, 'MSIE 7') :
if ($data['ie7_switch'] == 1 && !empty($data['ie7_theme'])) {
$ats_active = 'ie7';
};
break;
case strpos($user_agent, 'MSIE 8') :
if ($data['ie8_switch'] == 1 && !empty($data['ie8_theme'])) {
$ats_active = 'ie8';
};
break;
default :
$ats_active = 0;
}
// Dev Mode Overide
if($data['dev_mode'] == 1) {
$ats_active = 1;
}
return $ats_active;
}
// Run active agents check
checkActive($ats_plugin);
if(!empty($ats_active)) {
function change_theme() {
global $ats_plugin;
global $ats_active;
global $the_theme;
if(!empty($ats_plugin['ie5_theme'])) {$ie5 = $ats_plugin['ie5_theme'];} else {$ie5 = null;}
if(!empty($ats_plugin['ie6_theme'])) {$ie6 = $ats_plugin['ie6_theme'];} else {$ie6 = null;}
if(!empty($ats_plugin['ie7_theme'])) {$ie7 = $ats_plugin['ie7_theme'];} else {$ie7 = null;}
if(!empty($ats_plugin['ie8_theme'])) {$ie8 = $ats_plugin['ie8_theme'];} else {$ie8 = null;}
$theme_key = array(
'ie5' => $ie5,
'ie6' => $ie6,
'ie7' => $ie7,
'ie8' => $ie8,
);
// Only one value should return
foreach ($theme_key as $browser => $selection ) {
if ($ats_active == $browser) {
$the_theme = $selection;
}
}
// Add the dev mode override
if(!empty($ats_plugin['dev_theme'])) {
$the_theme = $ats_plugin['dev_theme'];
}
return $the_theme;
}
add_filter('template', 'change_theme');
add_filter('option_template', 'change_theme');
add_filter('option_stylesheet', 'change_theme');
}
}
// For non-IE browsers, we check if the user is an admin and enable developer mode
if ( !$is_IE && current_user_can('manage_options') ) {
if($ats_plugin['dev_mode'] == 1 && !empty($ats_plugin['dev_theme'])) {
$the_theme = $ats_plugin['dev_theme'];
}
function dev_theme() {
global $the_theme;
return $the_theme;
}
/* #todo if the theme is in developer mode, there should be a visual warning as a reminder */
if ($ats_plugin['dev_mode'] == 1) {
add_filter('template', 'dev_theme');
add_filter('option_template', 'dev_theme');
add_filter('option_stylesheet', 'dev_theme');
}
}
I've been staring at this for too long... it's completely inefficient. I'm literally running the entire switch statement once, then checking if active is flagged, then I'm running it again. That's so very wrong. I desperately need a bit of perspective on the right way to structure the logic.
Background Information:
It's switching the theme based on a user agent as configured in a WP Plugin admin. The theme has a dev mode for configuring the plugin and an active mode for the user agents.
$ats_plugin grabs the Redux array
$the_theme grabs the selected theme from that array
$active grabs the switch for whether or not a theme is being served to that user agent.
The whole mess is being filtered back into WordPress on the end.
Here's my mess of code. It works but it's horribly inefficient.
Original Madhouse Logic:
<?php
/**
* Define some early logic, which should probably be moved to a class later
*/
// Initialize the main variables
$active = 0;
$the_theme = null;
function swapTheme()
{
// Fetch the plugin options array
global $ats_plugin;
global $the_theme;
global $active;
// Fetch the user agent
$user_agent = $_SERVER['HTTP_USER_AGENT'];
// Assign variables based on user agent
switch ($user_agent) {
case strpos($user_agent, 'MSIE 5') :
$active = $ats_plugin['ie5_switch'];
$the_theme = $ats_plugin['ie5_theme'];
break;
case strpos($user_agent, 'MSIE 6') :
$active = $ats_plugin['ie6_switch'];
$the_theme = $ats_plugin['ie6_theme'];
break;
case strpos($user_agent, 'MSIE 7') :
$active = $ats_plugin['ie7_switch'];
$the_theme = $ats_plugin['ie7_theme'];
break;
case strpos($user_agent, 'MSIE 8') :
$active = $ats_plugin['ie8_switch'];
$the_theme = $ats_plugin['ie8_theme'];
break;
default :
// Check for Developer Mode
if ($ats_plugin['dev_mode'] == 1) {
$active = 1;
// Check for Developer Theme
if (!empty($ats_plugin['dev_theme']) && current_user_can('manage_options')) {
$the_theme = $ats_plugin['dev_theme'];
} else {
$the_theme = null;
}
}
break;
}
return $the_theme;
}
swapTheme();
if (!empty($the_theme) && $active == 1) {
add_filter('template', 'swapTheme');
add_filter('option_template', 'swapTheme');
add_filter('option_stylesheet', 'swapTheme');
}
I'm putting my super humble student goggles on right now.
Screenshots of what I'm doing
OK, first of all, do not run swapTheme() outside of any filter. Second, just check if you already matched something and than simple return.
function swapTheme() {
if ( ! empty( $the_theme ) ) {
return;
}
// ...
}
While it's not exactly the answer I was hoping for, further iteration and a bit of banter with the guys at Redux Framework got things into a working state. The Alternate Theme Switcher code is now at Github if you'd like to see how I resolved the myriad issues that came up. I'd still like to further refactor things going forward but the question of "how to fix broken?" no longer needs to be active here.
Thanks for the input that was provided.
Related
I'm new to prestashop and I'm having major trouble removing the address(I want to have only Summary=Shrnutí, Login/Guest Checkout=Přihlásit se, Delivery=Doručení and Payment=Platba here https://www.enakupak.cz/objednavka?step=1) step,. I am using prestashop 1.6.1.5
I know I have to modify order-carrier.tpl file and have followed several posts here and there but couldn't get it done right.
Does any of you have any actual idea on how to do this ?
I think that it will be change in this part of OrderController.php but dont know how to concretly change it
switch ((int)$this->step) {
case OrderController::STEP_SUMMARY_EMPTY_CART:
$this->context->smarty->assign('empty', 1);
$this->setTemplate(_PS_THEME_DIR_.'shopping-cart.tpl');
break;
case OrderController::STEP_DELIVERY:
if (Tools::isSubmit('processAddress')) {
$this->processAddress();
}
$this->autoStep();
$this->_assignCarrier();
$this->setTemplate(_PS_THEME_DIR_.'order-carrier.tpl');
break;
case OrderController::STEP_PAYMENT:
// Check that the conditions (so active) were accepted by the customer
$cgv = Tools::getValue('cgv') || $this->context->cookie->check_cgv;
if ($is_advanced_payment_api === false && Configuration::get('PS_CONDITIONS')
&& (!Validate::isBool($cgv) || $cgv == false)) {
Tools::redirect('index.php?controller=order&step=2');
}
if ($is_advanced_payment_api === false) {
Context::getContext()->cookie->check_cgv = true;
}
// Check the delivery option is set
if ($this->context->cart->isVirtualCart() === false) {
if (!Tools::getValue('delivery_option') && !Tools::getValue('id_carrier') && !$this->context->cart->delivery_option && !$this->context->cart->id_carrier) {
Tools::redirect('index.php?controller=order&step=2');
} elseif (!Tools::getValue('id_carrier') && !$this->context->cart->id_carrier) {
$deliveries_options = Tools::getValue('delivery_option');
if (!$deliveries_options) {
$deliveries_options = $this->context->cart->delivery_option;
}
foreach ($deliveries_options as $delivery_option) {
if (empty($delivery_option)) {
Tools::redirect('index.php?controller=order&step=2');
}
}
}
}
$this->autoStep();
// Bypass payment step if total is 0
if (($id_order = $this->_checkFreeOrder()) && $id_order) {
if ($this->context->customer->is_guest) {
$order = new Order((int)$id_order);
$email = $this->context->customer->email;
$this->context->customer->mylogout(); // If guest we clear the cookie for security reason
Tools::redirect('index.php?controller=guest-tracking&id_order='.urlencode($order->reference).'&email='.urlencode($email));
} else {
Tools::redirect('index.php?controller=history');
}
}
$this->_assignPayment();
if ($is_advanced_payment_api === true) {
$this->_assignAddress();
}
// assign some informations to display cart
$this->_assignSummaryInformations();
$this->setTemplate(_PS_THEME_DIR_.'order-payment.tpl');
break;
default:
$this->_assignSummaryInformations();
$this->setTemplate(_PS_THEME_DIR_.'shopping-cart.tpl');
break;
}
What if you cann this code after first case - break:
case OrderController::STEP_SUMMARY_EMPTY_CART:
$this->context->smarty->assign('empty', 1);
$this->setTemplate(_PS_THEME_DIR_.'shopping-cart.tpl');
break;
After this case add this case:
case OrderController::STEP_ADDRESSES:
$this->_assignAddress();
$this->processAddressFormat();
if (Tools::getValue('multi-shipping') == 1) {
$this->_assignSummaryInformations();
$this->context->smarty->assign('product_list', $this->context->cart->getProducts());
$this->setTemplate(_PS_THEME_DIR_.'order-address-multishipping.tpl');
} else {
$this->autoStep();
$this->_assignCarrier();
$this->setTemplate(_PS_THEME_DIR_.'order-carrier.tpl');
}
break;
Check, is it work.
I am trying to extend a Pico navigation plugin to exclude items from the navigation tree where the page's utilizes Twig template engine header tags.
My question is how do I get specific header tags from the .md files in the below PHP function and filter them to be excluded in the navigation tree?
The plugin currently implements the ability to omit items (pages and folders) from the tree with the following settings in a config.php file:
// Exclude pages and/or folders from navigation header
$config['navigation']['hide_page'] = array('a Title', 'another Title');
$config['navigation']['hide_folder'] = array('a folder', 'another folder');
The current function in the plugs' file uses the above config.php as follows:
private function at_exclude($page) {
$exclude = $this->settings['navigation'];
$url = substr($page['url'], strlen($this->settings['base_url'])+1);
$url = (substr($url, -1) == '/') ? $url : $url.'/';
foreach ($exclude['hide_page'] as $p) {
$p = (substr($p, -1*strlen('index')) == 'index') ? substr($p, 0, -1*strlen('index')) : $p;
$p = (substr($p, -1) == '/') ? $p : $p.'/';
if ($url == $p) {
return true;
}
}
foreach ($exclude['hide_folder'] as $f) {
$f = (substr($f, -1) == '/') ? $f : $f.'/';
$is_index = ($f == '' || $f == '/') ? true : false;
if (substr($url, 0, strlen($f)) == $f || $is_index) {
return true;
}
}
return false;
}
I need to add the ability of omitting items (or pages) from the tree using the Twig header tags 'Type' and 'Status' like so in the .md files:
/*
Title: Post01 In Cat01
Description: This post01 in cat01
Date: 2013-10-28
Category:
Type: post // Options: page, post, event, hidden
Status: draft // Options: published, draft, review
Author: Me
Template:
*/
...
The MarkDown content . . .
So if a user wants to remove items tagged with "post" in the 'type' tag and/or "draft" from the 'draft' tag (see header above), they would then add the linked tags in the array below that I added into the config.php:
// Exclude taged items:
$config['navigation']['hide_status'] = array('draft', 'maybe some other status tag');
$config['navigation']['hide_type'] = array('post', 'etc');
I also added the following to the bottom of the at_exclude() function:
private function at_exclude($page) {
. . .
foreach ($exclude['hide_staus'] as $s) {
$s = $headers['status'];
if ($s == 'draft' || 'review') {
return true;
}
}
foreach ($exclude['hide_type'] as $t) {
$t = $headers['type'];
if ($t == 'post' || 'hidden') {
return true;
}
return true;
}
. . .
This is obviously not working for me (because my PHP knowledge is limited). Any help with what I am missing, doing wrong or how I can add this functionality will be greatly appreciated.
I dived into the (not so beautiful) Pico code and those are my findings.
First of all, Pico doesn't read every custom field you add to the content header.
Instead, it has an internal array of fields to parse. Luckily, an hook called before_read_file_meta is provided to modify the array.
In at_navigation.php we'll add:
/**
* Hook to add custom file meta to the array of fields that Pico will read
*/
public function before_read_file_meta(&$headers)
{
$headers['status'] = 'Status';
$headers['type'] = 'Type';
}
This will result in Pico reading the headers, but it won't add the fields to the page data yet. We need another hook, get_page_data. In the same file:
/**
* Hook to add the custom fields to the page data
*/
public function get_page_data(&$data, $page_meta)
{
$data['status'] = isset($page_meta['status']) ? $page_meta['status'] : '';
$data['type'] = isset($page_meta['type']) ? $page_meta['type'] : '';
}
Now, in the at_exclude function, we can add the new logic.
(Instead of cycling, We configure an array of status and types we want to exclude, and we'll check if there is a match with the current page status/type)
private function at_exclude($page)
{
[...]
if(in_array($page['status'], $exclude['status']))
{
return true;
}
if(in_array($page['type'], $exclude['type']))
{
return true;
};
return false;
}
Now let's customize our config.php (I standardized the configuration with the plugin standards):
$config['at_navigation']['exclude']['status'] = array('draft', 'review');
$config['at_navigation']['exclude']['type'] = array('post');
All done!
But if you are just starting out, I'd advise you to use a more mature and recent flat file cms. Unless you are stuck with PHP5.3
I decided to simplify the function to omit it from the config.php since it really isn't needed to be set by the end-user. By doing so, the at_exclude() function is much simpler and quicker on the back-end by omitting all the checks via other files:
at_exclude {
. . .
$pt = $page['type'];
$ps = $page['status'];
$home = ($pt == "home");
$post = ($pt == "post");
$event = ($pt == "event");
$hide = ($pt == "hide");
$draft = ($ps == "draft");
$review = ($ps == "review");
$type = $home || $post || $event || $hide;
$status = $draft || $review;
if ( $type || $status ) {
return true;
};
return false;
}
Obviously it needs some tidying up but you get the picture. Thnx
I've got this function in my Wordpress theme directory:
function variable($value) {
$country_code = '';
require_once("geoip.inc");
$gi = geoip_open(dirname(__FILE__)."/GeoIP.dat",GEOIP_STANDARD);
$country_code = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);
geoip_close($gi);
switch ($value) {
case 'prem_no':
if ($country_code == 'US') { $prem_no = '888-888-8888'; }
elseif ($country_code == 'AU') { $prem_no = '1900 000 000'; }
else { $prem_no = '0906 636 4355'; }
return $prem_no;
break;
case 'prem_rate':
if ($country_code == 'US') { $prem_rate = '$3.50'; }
elseif ($country_code == 'AUS') { $prem_rate = '$3.96'; }
else { $prem_rate = '£1.53'; }
return $prem_rate;
break;
case 'local_no':
if ($country_code == 'US') { $local_no = '755-555-5555'; }
elseif ($country_code == 'AUS') { $local_no = '1800 000 000'; }
else { $local_no = '0207 111 6311'; }
return $local_no;
break;
case 'sms_no':
if($country_code == 'AUS') { $sms_no = '1977 1977'; }
else { $sms_no = '78887'; }
return $sms_no;
break;
case 'sms_rate':
if($country_code == 'AUS') { $sms_rate = '25c'; }
else { $sms_rate = '£1.50'; }
return $sms_rate;
break;
case 'helpline':
if($country_code == 'US') { $helpline = '700-777-7777'; }
elseif ($country_code == 'AUS') { $helpline = '1700 000 000'; }
else { $helpline = '0207 111 6210'; }
return $helpline;
break;
default:
break;
}
}
This works fine for normal pages, and loads all the files listed above, and the switch works fine. However, when I go to view the blog articles I just get a blank page with the error message:
Warning: fopen(GeoIP.dat): failed to open stream: No such file or directory in C:\wamp\www\clairvoyant\wp-content\themes\clairvoyant\geoip.inc on line 314
and I can't work out why it would be different for normal pages and blog pages.
I know there are individual PHP files, but they all use the same functions file, right?
It's the GeoIP.dat it can't find, and it was doing this before last week before I added dirname(FILE) just before the filename.
The only difference I can think of, is my permalinks have a custom structure of /blog/%postname% - could the /blog be affecting the path somehow?
Any ideas as to why it's not working as expected just on blog pages?
UPDATE:
This is relevant function inside geoip.inc:
function geoip_open($filename, $flags) {
$gi = new GeoIP;
$gi->flags = $flags;
if ($gi->flags & GEOIP_SHARED_MEMORY) {
$gi->shmid = #shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
} else {
$gi->filehandle = fopen($filename,"rb") or die( "Oops! Can not open $filename\n" );
if ($gi->flags & GEOIP_MEMORY_CACHE) {
$s_array = fstat($gi->filehandle);
$gi->memory_buffer = fread($gi->filehandle, $s_array['size']);
}
}
$gi = _setup_segments($gi);
return $gi;
}
BUMP: Can anyone throw some light on this? Wordpress seems to be stripping the path of $filename when viewing blog pages. When viewing normal pages, the full path is included.
I finally found out what was creating the different output between pages.
The wordpress blog pages were being generated using a separate index.php file than the other pages - this was down to the way the template I'm using worked.
On the blog index.php template, the filename was actually being hardcoded into the index file.
Removed that, and now just the function is being used in both, all is well!
Thanks to all for your help
In my Wordpress theme I have a function that looks a bit like this:
function variable($value) {
switch ($value) {
case 'prem_no':
$prem_no_uk = '0906 636 4355';
$prem_no_aus = '';
$prem_no_us = '';
return $prem_no;
break;
}
}
On the page I am calling:
echo variable('prem_no');
I want to use this script to get the users location, and depending on the returning location, return one of the three variables listed in the case above.
http://www.hostip.info/use.html
the problem I have, is I've looked on that site, and it just gives a URL. I don't know how to write an IF statement, or whatever is needed.
I think logically, I want to only have one call for the main location finder, then store that value as a variable elsewhere on the site.
Then in the return for the cases add a suffix at the end of prem_no that would match the cases above.
Is that along the right tracks?
UPDATE:
Right I'll try and have a go in a slightly different direction.
At the top of the header file I've got this:
require_once 'geoip.inc';
$gi = geoip_open('GeoIP.dat',GEOIP_STANDARD);
$country_code = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);
geoip_close($gi);
I'm getting a error message saying:
Warning: fopen(GeoIP.dat): failed to open stream: No such file or directory in C:\wamp\www\clairvoyant\wp-content\themes\clairvoyant\geoip.inc on line 314
What I don't get is that the path is absolutely correct, the file is there. So why can't it find it?
Okay, so I've managed to partly fix my issues here.
I put the switch and the code into a single function like this:
function variable($value) {
$country_code = '';
require_once("geoip.inc");
$gi = geoip_open(dirname(__FILE__)."/GeoIP.dat",GEOIP_STANDARD);
$country_code = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);
geoip_close($gi);
switch ($value) {
case 'prem_no':
if ($country_code == 'US') { $prem_no = '888-888-8888'; }
elseif ($country_code == 'AU') { $prem_no = '1900 000 000'; }
else { $prem_no = '0906 636 4355'; }
return $prem_no;
break;
case 'prem_rate':
if ($country_code == 'US') { $prem_rate = '$3.50'; }
elseif ($country_code == 'AUS') { $prem_rate = '$3.96'; }
else { $prem_rate = '£1.53'; }
return $prem_rate;
break;
case 'local_no':
if ($country_code == 'US') { $local_no = '755-555-5555'; }
elseif ($country_code == 'AUS') { $local_no = '1800 000 000'; }
else { $local_no = '0207 111 6311'; }
return $local_no;
break;
case 'sms_no':
if($country_code == 'AUS') { $sms_no = '1977 1977'; }
else { $sms_no = '78887'; }
return $sms_no;
break;
case 'sms_rate':
if($country_code == 'AUS') { $sms_rate = '25c'; }
else { $sms_rate = '£1.50'; }
return $sms_rate;
break;
case 'helpline':
if($country_code == 'US') { $helpline = '700-777-7777'; }
elseif ($country_code == 'AUS') { $helpline = '1700 000 000'; }
else { $helpline = '0207 111 6210'; }
return $helpline;
break;
default:
break;
}
}
The file GeoIP.dat loads perfectly fine on every normal page, except when looking at the blog pages. (I'm assuming it must read functions differently or something? The error I get when trying to view the Blog loop articles is:
Warning: fopen(GeoIP.dat): failed to open stream: No such file or directory in C:\wamp\www\clairvoyant\wp-content\themes\clairvoyant\geoip.inc on line 314
then at the bottom of the trace table it says
Can not open GeoIP.dat
I just can't work out why it's working fine for normal pages, but not for blogs. Can anyone shed any light?
UPDATE:
It turns out Wordpress uses different pages for blog and normal pages. So I just needed to edit the other pages to match the initial ones, and it all seems to be working now.
Thanks for all of those who took the time to read my questions, sorry if it wasn't too clear or logical. But thanks anyway. All is good!
After thinking about This Question and giving an answer to it I wanted to do more about that to train myself.
So I wrote a function which will calc the length of an given function. Th given php-file has to start at the beginning of the needed function.
Example: If the function is in a big phpfile with lots of functions, like
/* lots of functions */
function f_interesting($arg) {
/* function */
}
/* lots of other functions */
then $part3 of my function will require to begin like that (after the starting-{ of the interesting function):
/* function */
}
/* lots of other functions */
Now that's not the problem, but I would like to know if there are an cleaner or simplier ways to do this. Here's my function: (I already cleaned a lot of testing-echo-commands)
(The idea behind it is explained here)
function f_analysis ($part3) {
if(isset($part3)) {
$char_array = str_split($part3); //get array of chars
$end_key = false; //length of function
$depth = 0; //How much of unclosed '{'
$in_sstr = false; //is next char inside in ''-String?
$in_dstr = false; //is nect char inside an ""-String?
$in_sl_comment = false; //inside an //-comment?
$in_ml_comment = false; //inside an /* */-comment?
$may_comment = false; //was the last char an '/' which can start a comment?
$may_ml_comment_end = false; //was the last char an '*' which may end a /**/-comment?
foreach($char_array as $key=>$char) {
if($in_sstr) {
if ($char == "'") {
$in_sstr = false;
}
}
else if($in_dstr) {
if($char == '"') {
$in_dstr = false;
}
}
else if($in_sl_comment) {
if($char == "\n") {
$in_sl_comment = false;
}
}
else if($in_ml_comment) {
if($may_ml_comment_end) {
$may_ml_comment_end = false;
if($char == '/') {
$in_ml_comment = false;
}
}
if($char == '*') {
$may_ml_comment_end = true;
}
}
else if ($may_comment) {
if($char == '/') {
$in_sl_comment = true;
}
else if($char == '*') {
$in_ml_comment = true;
}
$may_comment = false;
}
else {
switch ($char) {
case '{':
$depth++;
break;
case '}':
$depth--;
break;
case '/':
$may_comment = true;
break;
case '"':
$in_dstr = true;
break;
case "'":
$in_sstr = true;
break;
}
}
if($depth < 0) {
$last_key = $key;
break;
}
}
} else echo '<br>$part3 of f_analysis not set!';
return ($last_key===false) ? false : $last_key+1; //will be false or the length of the function
}
Tokenizer (Example) - Learn it, love it.
You could probably reduce the number of state variables a little, but truthfully... yes, it will be messy code. I would probably get rid of $may_ml_comment_end and peek ahead for the next character when I encounter an asterisk, for example. You will need to rewrite your foreach loop to a regular for loop be able to do that without creating a bigger mess though.
PS: I don't see you handling the escape character yet. Without the above approach, that would introduce another boolean variable.
Another problem with your current code is that characters immediately following a / don't get interpreted as they should. However unlikely
echo 5/'2'; // NB: no space in between
is valid in PHP and would break your parser.