I've updated a website and found an annoying problem in my pages
I resolved it, but i'm not realy convinced it should look like this.
To me i'm not an PHP expert its strange behaviour could someone explain me whats going on.
I had this code:
if($Menu == "index"){
{if ($Language == "UK"){echo "<td><h1>Welcome</h1>";}
{if ($Language == "NL"){echo "<td><h1>Welkom </h1>";}
}
else
// if $menu was not index it displayed a hyperlink to Welcome page
The string thing here that while the checking for language worked fine.
The comparison for $Menu did not work, even if it contained the word index
As the whole page was generated on the fly and some string operations where done before
I assumed that maybe, despite i also tested it with
echo "dump Menu variable " . $Menu
Which resulted in jut displaying the word index on the page. So maybe there would go something wrong in string types or something like that
So i experimented with
if($Menu === "index")
No luck
Well i finally solved it like this
if (strpos($Menu,'index' !==false)
Is that really the way it should be done???, I don't feel really comfortable with it.
As to me its strange that for $Language it just works as it should (in my opinion).
Is there is some type problem here, or maybe unwanted endings \n could i perhaps ehm normalize the string to do a content of readable string comparions or, a different type of equal operator. As it feels to me as $Menu could be handled more easily. Maybe a reformat or but i'm not sure here.
Looks indeed like your index-String is containing whitespaces, instead of strpos you could use trim( $Menu ) to get rid of them.
But the best would be to prevent their occurence. You could try echo "dump Menu variable |" . $Menu ."|"; or just var_dump( $Menu ) to identify the additional characters.
Maybe you could post, your code-segment where $Menu is filled.
(sorry can't just comment)
You can try something like this
$Menu = trim($Menu);
$Language = trim($Language);
$langAllowed = ["UK", "NL"]; // zero element is default;
if(!in_array($Language, $langAllowed )) $Language = $langAllowed[0];
$menuLocales=[
"index" => [
"UK"=>"Welcome",
"NL"=>"Welkom "
],
"default"=>[
"UK"=>"Welcome default (no index)",
"NL"=>"Welkom default (no index)"
]
];
$MenuIndex = isset($menuLocales[ $Menu ]) ? $Menu : "default";
echo "<td><h1>".$menuLocales[ $MenuIndex ][ $Language ]."</h1>";
Related
I used to code with Groovy ... I found that this 'feature' (no idea what they called it) so fun n nice (I heard they implemented this on C# too).
for example ... I want to display person neighbour name
I just type
println person?.neigbour?.name ;
it means if the neighbour is empty / blank .. it didn't display anything .
how to do this in php 5/yii?
example:
instead of typing long codes like
'/>
Would it be better to type like
'/>
In the first place I think this is no Yii issue, but simply PHP. Assuming, that you use Yii with nice models, there it would go sth like this:
if($person && $person->neighbour && !empty($person->neighbour->name)) {
echo $person->neighbour->name;
}
a shortcut for this may be (not so nice):
echo $person ? ($person->neighbour ? ($person->neighbour->name ? $person->neighbour->name : "" ) : "" ) : "";
use empty()
check:
if(!empty($variable))
{
//show fields here
}
I have some images in my database
http://***.com/2013/12/reign-death-midseason-finale-featured.jpg?w=500
http://***.com/reign-death-midseason-finale-featured.png?w=120
http://***.com/2013/12/finale-featured.jpg?w=50
http://***.com/2013/finale-featured.jpg?w=50&h=50
http://***.com/2013/12/reign-death-midseason-finale-featured.jpg
I want to change the images with w= to same width and ?w=50&h=50 also. all with W should come as w=600 and w=600&h=600. This is what I was trying str_replace but there is a problem with this that w= always change and in some cases there is height also and it also need to be changed, i have search net and found that it can be done with preg_replace don't know how.
EDIT
Answer needed is if(hight is null) result is case 1 w=600 and if h is not null case 2 w=600&h=600
please help
Sorry it took me a while, I was kinda busy
try the following
$pattern = '~(?<=\W(w|h)\=)(\d+?)(?=\D|$)~';
$replace = '600';
$subject = 'http://localhost/2013/finale-featured.jpg?w=50&h=50';
echo preg_replace($pattern,$replace,$subject);
try this with many variations of your URIs
PS: this kind of advanced string finding/replacing is the domain of regular expressions. If you find you need to do a lot of this, consider starting to learn about them, it's a whole language in itself. I used some assertions (lookahead (?<=) and lookbehind (?=)) for this particular solution
If you want to avoid using a regular expression you can parse the URL and query string into arrays, which would make evaluating the query string values much easier.
$url = 'http://***.com/2013/finale-featured.jpg?w=50&h=50';
$urlArray = parse_url($url);
parse_str($urlArray['query'], $queryStringArray);
if ( !isset($queryStringArray['h']) || $queryStringArray['h'] === null ) {
} else if ( ... ) {
} else if ( ... ) {
}
I’ve tried for some time now to solve what probably is a small issue but I just can’t seem get my head around it. I’ve tried some different approaches, some found at SO but none has worked yet.
The problem consists of this:
I’ve a show-room page where I show some cloth. On each single item of cloth there is four “views”
Male
Female
Front
Back
Now, the users can filter this by either viewing the male or female model but they can also filter by viewing front or back of both gender.
I’ve created my script so it detects the URL query and display the correct data but my problem is to “build” the URL correctly.
When firstly enter the page, the four links is like this:
example.com?gender=male
example.com?gender=female
example.com?site=front
example.com?site=back
This work because it’s the “default” view (the default view is set to gender=male && site=front) in the model.
But if I choose to view ?gender=female the users should be able to filter it once more by adding &site=back so the complete URL would be: example.com?gender=female&site=back
And if I then press the link to see gender=male it should still keep the URL parameter &site=back.
What I’ve achived so far is to append the parameters to the existing URL but this result in URL strings like: example.com?gender=male&site=front&gender=female and so on…
I’ve tried but to use the parse_url function, the http_build_query($parms) method and to make my “own” function that checks for existing parameters but it does not work.
My latest try was this:
_setURL(‘http://example.com?gender=male’, ‘site’, ‘back’);
function _setURL($url, $key, $value) {
$separator = (parse_url($url, PHP_URL_QUERY) == NULL) ? '?' : '&';
$query = $key."=".$value;
$url .= $separator . $query;
var_dump($url); exit;
}
This function works unless the $_GET parameter already exists and thus should be replaced and not added.
I’m not sure if there is some “best practice” to solve this and as I said I’ve looked at a lot of answers on SO but none which was spot on my issue.
I hope I’ve explained myself otherwise please let me know and I’ll elaborate.
Any help or advice would be appreciated
You can generate the links dynamically using the following method:
$frontLink = (isset($_GET['gender'])) ? 'mydomain.com?gender='.$_GET['gender'].'&site=front':'mydomain.com?site=front';
$backLink = (isset($_GET['gender'])) ? 'mydomain.com?gender='.$_GET['gender'].'&site=back':'mydomain.com?site=back';
This is a 1 line if statement which will set the value of the variables $frontLink and $backlink respectively. The syntax for a 1 line if statement is $var = (if_statement) ? true_result:false_result; this will set the value of $var to the true_result or false_result depending on the return value of the if statement.
You can then do the same for the genders:
$maleLink = (isset($_GET['site'])) ? 'mydomain.com?gender=male&site='.$_GET['site']:'mydomain.com?gender=male';
$femaleLink = (isset($_GET['site'])) ? 'mydomain.com?gender=female&site='.$_GET['site']:'mydomain.com?gender=female';
Found this by searching for a better solution then mine and found this ugly one (That we see a lot on the web), so here is my solution :
function add_get_parameter($arg, $value)
{
$_GET[$arg] = $value;
return "?" . http_build_query($_GET);
}
<?php
function requestUriAddGetParams(array $params)
{
$parseRes=parse_url($_REQUEST['REQUEST_URI']);
$params=array_merge($_GET, $params);
return $parseRes['path'].'?'.http_build_query($params);
}
?>
if(isset($_GET['diagid']) && $_GET['diagid']!='') {
$repParam = "&diagid=".$_GET['diagid'];
$params = str_replace($repParam, "", $_SERVER['REQUEST_URI']);
$url = "http://".$_SERVER['HTTP_HOST'].$params."&diagid=".$ID;
}
else $url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."&diagid=".$ID;
I am storing HTML layouts within a MySQL database. These layouts may contain tags within the HTML as show below..
{site.poll="fred,joe,john"}
and
{site.layout.header}
Currently i am searching the HTML template by executing multiple preg_matches to identify the tags, looping through the array then executing a str_replace(), replacing with another partial html template also pulled back from the db.. Example below..
if (preg_match_all('/{site\.layout\.(.)*}/', $data, $match) != FALSE)
{
foreach($match[0] as $value)
{
$value = trim($value, '{}');
$tmp_store = explode('.', $value);
$tmp_partial = $this->parse($this->get_layout(end($tmp_store)));
$data = str_replace('{'. $value .'}', $tmp_partial, $data);
}
}
I would need to execute a regex for each tag i required, then execute a str_replace on each instance of that tag.. The same again would need doing for each required partial template..
To me, this is all seeming to get heavy..
Is there a better way of doing this?
Thanks in advance..
Edit: I do not want to use an existing library, i would like to do this task myself and learn in the process..
Well you could use preg_replace to find and replace your tags in one shot.
The best approach in my opinion would be to use an existing template system such as Twig or Smarty. I know for sure that you can read data into Smarty (it doesn't have to be from a file). I'm sure Twig has something similar.
Twig and Smarty also provide caching options so you aren't rebuilding your template on every request. However they work best if the templates are stored in files.
If you really must roll your own template system you should build some kind of parser that actually checks the content character by character. This will likely be faster and more accurate than regular expressions (though more complex)
I don't expect this to answer your question as such, but thought it might give you something else to think about. Some code I've got for when my template class is overkill.
function replace_tags(&$xhtml, $tags) {
if( is_array($tags) && count($tags) > 0 )
foreach ($tags as $tag => $data) {
$xhtml = str_replace("{{" . $tag . "}}", $data, $xhtml);
}
if( $xhtml ) return $xhtml;
}
$tpl = "/templates/index.xhtml";
$tags = array(
"css" => null,
"js" => null,
"main_content" => null
);
$tags['main_content'] = file_get_contents("/home/main.xhtml");
echo replace_tags(file_get_contents($tpl), $tags);
edit
Thought I'd clarify on the reason the function receives $xhtml by reference, and also returns $xhtml. Basically just to make it dual purpose.
//Usage at the end of a page
echo replace_tags(file_get_contents($tpl), $tags);
//Usage for template in template
$tags['menu'] = file_get_contents($menu_tpl);
replace_tags($tags['menu'], $tags);
echo replace_tags(file_get_contents($tpl), $tags);
UPDATE:
Thank you all for your input. Some additional information.
It's really just a small chunk of markup (20 lines) I'm working with and had aimed to to leverage a regex to do the work.
I also do have the ability to hack up the script (an ecommerce one) to insert the classes as the navigation is built. I wanted to limit the number of hacks I have in place to keep things easier on myself when I go to update to the latest version of the software.
With that said, I'm pretty aware of my situation and the various options available to me. The first part of my regex works as expected. I posted really more or less to see if someone would say, "hey dummy, this is easy just change this....."
After coming close with a few of my efforts, it's more of the principle at this point. To just know (and learn) a solution exists for this problem. I also hate being beaten by a piece of code.
ORIGINAL:
I'm trying to leverage regular expressions to add a CSS a class to the first and last list items within an ordered list. I've tried a bunch of different ways but can't produce the results I'm looking for.
I've got a regular expression for the first list item but can't seem to figure a correct one out for the last. Here is what I'm working with:
$patterns = array('/<ul+([^<]*)<li/m', '/<([^<]*)(?<=<li)(.*)<\/ul>/s');
$replace = array('<ul$1<li class="first"','<li class="last"$2$3</ul>');
$navigation = preg_replace($patterns, $replace, $navigation);
Any help would be greatly appreciated.
Jamie Zawinski would have something to say about this...
Do you have a proper HTML parser? I don't know if there's anything like hpricot available for PHP, but that's the right way to deal with it. You could at least employ hpricot to do the first cleanup for you.
If you're actually generating the HTML -- do it there. It looks like you want to generate some navigation and have a .first and .last kind of thing on it. Take a step back and try that.
+1 to generating the right html as the best option.
But a completely different approach, which may or may not be acceptable to you: you could use javascript.
This uses jquery to make it easy ...
$(document).ready(
function() {
$('#id-of-ul:firstChild').addClass('first');
$('#id-of-ul:lastChild').addClass('last');
}
);
As I say, may or may not be any use in this case, but I think its a valid solution to the problem in some cases.
PS: You say ordered list, then give ul in your example. ol = ordered list, ul = unordered list
You wrote:
$patterns = array('/<ul+([^<]*)<li/m','/<([^<]*)(?<=<li)(.*)<\/ul>/s');
First pattern:
ul+ => you search something like ullll...
The m modifier is useless here, since you don't use ^ nor $.
Second pattern:
Using .* along with s is "dangerous", because you might select the whole document up to the last /ul of the page...
And well, I would just drop s modifier and use: (<li\s)(.*?</li>\s*</ul>) with replace: '$1class="last" $2'
In view of above remarks, I would write the first expression: <ul.*?>\s*<li
Although I am tired of seeing the Jamie Zawinski quote each time there is a regex question, Dustin is right in pointing you to a HTML parser (or just generating the right HTML from the start!): regexes and HTML doesn't mix well, because HTML syntax is complex, and unless you act on a well known machine generated output with very predictable result, you are prone to get something breaking in some cases.
I don't know if anyone cares any longer, but I have a solution that works in my simple test case (and I believe it should work in the general case).
First, let me point out two things: While PhiLho is right in that the s is "dangerous", since dots may match everything up to the final of the document, this may very well be what you want. It only becomes a problem with not well formed pages. Be careful with any such regex on large, manually written pages.
Second, php has a special meaning of backslashes, even in single quotes. Most regexen will perform well either way, but you should always double-escape them, just in case.
Now, here's my code:
<?php
$navigation='<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
<li>Beer</li>
<li>Water</li>
</ul>';
$patterns = array('/<ul.*?>\\s*<li/',
'/<li((.(?<!<li))*?<\\/ul>)/s');
$replace = array('$0 class="first"',
'<li class="last"$1');
$navigation = preg_replace($patterns, $replace, $navigation);
echo $navigation;
?>
This will output
<ul>
<li class="first">Coffee</li>
<li>Tea</li>
<li>Milk</li>
<li>Beer</li>
<li class="last">Water</li>
</ul>
This assumes no line feeds inside the opening <ul...> tag. If there are any, use the s modifier on the first expression too.
The magic happens in (.(?<!<li))*?. This will match any character (the dot) that is not the beginning of the string <li, repeated any amount of times (the *) in a non-greedy fashion (the ?).
Of course, the whole thing would have to be expanded if there is a chance the list items already have the class attribute set. Also, if there is only one list item, it will match twice, giving it two such attributes. At least for xhtml, this would break validation.
You could load the navigation in a SimpleXML object and work with that. This prevents you from breaking your markup with some crazy regex :)
As a preface .. this is waaay over-complicating things in most use-cases. Please see other answers for more sanity :)
Here is a little PHP class I wrote to solve a similar problem. It adds 'first', 'last' and any other classes you want. It will handle li's with no "class" attribute as well as those that already have some class(es).
<?php
/**
* Modify list items in pre-rendered html.
*
* Usage Example:
* $replaced_text = ListAlter::addClasses($original_html, array('cool', 'awsome'));
*/
class ListAlter {
private $classes = array();
private $classes_found = FALSE;
private $count = 0;
private $total = 0;
// No public instances.
private function __construct() {}
/**
* Adds 'first', 'last', and any extra classes you want.
*/
static function addClasses($html, $extra_classes = array()) {
$instance = new self();
$instance->classes = $extra_classes;
$total = preg_match_all('~<li([^>]*?)>~', $html, $matches);
$instance->total = $total ? $total : 0;
return preg_replace_callback('~<li([^>]*?)>~', array($instance, 'processListItem'), $html);
}
private function processListItem($matches) {
$this->count++;
$this->classes_found = FALSE;
$processed = preg_replace_callback('~(\w+)="(.*?)"~', array($this, 'appendClasses'), $matches[0]);
if (!$this->classes_found) {
$classes = $this->classes;
if ($this->count == 1) {
$classes[] = 'first';
}
if ($this->count == $this->total) {
$classes[] = 'last';
}
if (!empty($classes)) {
$processed = rtrim($matches[0], '>') . ' class="' . implode(' ', $classes) . '">';
}
}
return $processed;
}
private function appendClasses($matches) {
array_shift($matches);
list($name, $value) = $matches;
if ($name == 'class') {
$value = array_filter(explode(' ', $value));
$value = array_merge($value, $this->classes);
if ($this->count == 1) {
$value[] = 'first';
}
if ($this->count == $this->total) {
$value[] = 'last';
}
$value = implode(' ', $value);
$this->classes_found = TRUE;
}
return sprintf('%s="%s"', $name, $value);
}
}