Regular expression to get page title - php

There are lots of answers to this question, but not a single complete one:
With using one regular expression, how do you extract page title from <title>Page title</title>?
There are several other cases how title tags are typed, such as:
<TITLE>Page title</TITLE>
<title>
Page title</title>
<title>
Page title
</title>
<title lang="en-US">Page title</title>
...or any combination of above.
And it can be on its own line or in between other tags:
<head>
<title>Page title</title>
</head>
<head><title>Page title</title></head>
Thanks for help in advance.
UDPATE: So, the regex approach might not be the best solution to this. Which PHP based HTML parser could handle all scenarios, where HTML is well formed (or not so well)?
UPDATE 2: sp00m's regex (https://stackoverflow.com/a/13510307/1844607) seems to be working in all cases. I'll get back to this if needed.

Use a HTML parser instead. But in case of:
<title[^>]*>(.*?)</title>
Demo

Use the DOMDocument class:
$doc = new DOMDocument();
$doc->loadHTML($html);
$titles = $doc->getElementsByTagName("title");
echo $titles->item[0]->nodeValue;

Use this regex:
<title>[\s\S]*?</title>

Related

PHP Regular expression to find scripts in head

I need regular expression to be used in PHP that can extract all script tags links (src attributes).
i already have this regex which i created to extract script src values but i'm unable to make it work to find only in the head section
/<script [^>]*src=["|\']([^"|\']+(\.js))/i
hoping someone will check this and test before sending a new regex that can work.
/html/head/script/#src
Easy peasy. Obviously not a regex, it's xpath. Not good things tend to happen when you try to parse HTML with regular expressions. Fortunately a more capable HTML parser comes with PHP's DOM extension - exposed by the loadHTML() and loadHTMLFile() methods.
This lets you work with all the wonderful DOM methods as well as XPath for querying the document.
Example:
$html = <<<'HTML'
<html>
<head>
<script src="foo.js"></script>
<script src="bar.js"></script>
</head>
<body>
<script src="baz.js"></script>
</body>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('/html/head/script/#src') as $src) {
echo $src->value, "\n";
}
Output:
foo.js
bar.js

php to strip and replace html meta tags

I'm not very familiar with PHP overall, but I'm trying to find a way to change some parts of the following documents:
index.html
hidden.html
Both pages are using the same header include file containing <meta name="robots" content="index, follow">
but I want to use PHP for some pages to strip and replace the entire line, and replace with something like <meta name="robots" content="none">
Can anyone provide an example of just stripping such a thing, and also strip+replace?
Would be greatly appreciated.
You can use str_replace to find and replace strings. See http://php.net/manual/en/function.str-replace.php
str_replace("I want to replace this", "with this");

What does these regular expressions mean in this code?

I was trying to change some parts of a joomla plugin, when I faced this part of it and I have no idea what it's doing.
Can someone please explain to me what these regular expressions and those ${4} do?
$comStart = '';
$comEnd = '';
$output = JResponse::getBody();
$output = preg_replace('/\<meta name=\"og\:/', '<meta property="og:', $output);
$output = preg_replace('/\<meta name=\"fb:admins/', '<meta property="fb:admins', $output);
$output = preg_replace('/<(\w+) (\w+)="(\w+):(\w+)" (\w+)="([a-zA-Z0-9\ \_\-\:\.\&\/\,\=\!\?]*)" \/>/i', $comStart.'<${1} ${2}="${3}:${4}" ${5}="${6}" >'.$comEnd, $output);
FYI: This plugin is for displaying facebook and opengraph tags inside articles.
SERIOUS NOTE!
The use of regular expressions to parse/match HTML/XML is highly
discouraged. Seriously, don't do it
Basically, it's a regular expression to parse/match HTML. Which may have slight side effects of not working, hard to maintain, and insanity.
The ${N} ones are called back-reference, they reference to the Nth brackets matched in the regular expressions.
If you require to do manipulation of HTML strings in PHP, you should use the DOMDocument class which was made exactly for this.
Example
<?php
$html_string = <<<HTML
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="target">
This is the target DIV! <span>This span will change texts!</span>
</div>
</body>
</html>
HTML;
$dom = new DOMDocument();
// Loading HTML from string...
$dom->loadHTML($html_string);
//Retrieve target and span elements
$target = $dom->getElementById("target");
$span = $target->getElementsByTagName("span")->item(0);
//Remove text, firstChild is the text node.
$span->removeChild($span->firstChild);
//Append new text
$span->appendChild(new DOMText("This is the new text!"));
//Change an attribute
$span->setAttribute("class", "spanny");
//Save HTML to string
$html_string = $dom->saveHTML();
echo $html_string;
Regular Expressions aren't bad, evil, or scary, they are simply the wrong tool for the job, you don't stick a nail with a jackhammer do you?
$output = preg_replace('/\<meta name=\"og\:/', '<meta property="og:', $output);
Replace the string <meta name="og: with <meta property="og:. Kind of pointless - regex is not needed here.
$output = preg_replace('/\<meta name=\"fb:admins/', '<meta property="fb:admins', $output);
Replace <meta name="fb:admins with <meta property="fb:admins. Just as pointless - regex is not needed here.
$output = preg_replace('/<(\w+) (\w+)="(\w+):(\w+)" (\w+)="([a-zA-Z0-9\ \_\-\:\.\&\/\,\=\!\?]*)" \/>/i', $comStart.'<${1} ${2}="${3}:${4}" ${5}="${6}" >'.$comEnd, $output);
Replace a string like <word1 word2="word3:word4" word5="word6withspecialcharacterslike-:.etc." /> with <word1 word2="word3:word4" word5=word6withspecialcharacterslike-:.etc." >. So it only removes a trailing slash before the closing >. Very suspect and Voodoo-like use of regex.
Also, all those regexes are highly inelegant (lots of pointless escapes, for example) and show that whoever wrote those doesn't know much about regexes. Letting something like this loose on HTML is asking for trouble.
AVOID! AVOID! AVOID!
Each (\w+) says find a word and store it. So you are doing this (in pseudocode)
find /(word1) (word2)="(word3)" (word4)="(manypossiblechars5)"/ignoring case
replace pattern with $comStart.<word1 word2="word3:word4" manypossiblechars5="word6">.$comEnd
The first one tries to replace tags of the form <meta name="og:... with <meta property="og:...
The second similarly replaces tags starting <meta name="fb:admins... with <meta property="fb:admins...
Finally, the third seems to take tags of the form <word word="word:word" word="something" \/> and wraps them with $comStart and $comEnd.
This is done by matching the parts of the tag (placing () around them) and then using backreferences such as ${4} to refer to the 4th matched part.
Here $comStart and $comEnd are set to '' so that seems a little pointless. It also manages to get rid of the closing slash for the tag at the same time, though who knows if that is intentional!
Those expressions attempt to fix the document head code by:
rewriting <meta name="og:*" to `
rewriting <meta name="fb:admins" to <meta property="fb:admins"
rewriting meta tags with a dangling slash to one without it (assuming it will always have two attributes.
This is just horrendous code, and as long as your templates don't have
those "mistakes" in them, you can throw this crap away.

PHP XPath and Line Numbers

The following xpath works, but how can i get the line number at which the xpath finds the p element with class 'blah'?
<?php
$doc = new DOMDocument();
$doc->loadHTML('<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
</head>
<body>
<p class='blah'>some text here</p>
</body>
</html>');
$xpath = new DOMXPath($doc);
$xpath_query = "//*[contains(#class, 'blah')]";
?>
XPath and DOM have no concept of a line number. They only see nodes, and the linkages between them.
The DOM object itself may have some internal metadata which can relate a node back to which line it was on in the source file, but you'd have to rummage around inside the object and the DOM source to find out. Doesn't seem to be anything mentioned at http://php.net/dom.
Alternatively, if the node you're looking at, and/or the surrounding HTML is fairly/totally unique in the document, you could search the raw html for the matching HTML text of the node and get a line number that way.

html to text with domdocument class

How to get a html page source code without htl tags?
For example:
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="hu"/>
<title>this is the page title</title>
<meta name="description" content="this is the description" />
<meta name="keywords" content="k1, k2, k3, k4" />
start the body content
<!-- <div>this is comment</div> -->
open
End now one noframes tag.
<noframes><span>text</span></noframes>
<select name="select" id="select"><option>ttttt</option></select>
<div class="robots-nocontent"><span>something</span></div>
<img src="url.png" alt="this is alt attribute" />
I need this result:
this is the page title this is the description k1, k2, k3, k4 start the body content this is title attribute open End now one noframes tag. text ttttt something this is alt attribute
I need too the title and the alt attributes.
Idea?
You could do it with a regex.
$regex = '/\<.\>/';
would be a very simple start to remove anything with < and > around it. But in order to do this, you're going to have to pull in the HTML as a file_get_contents() or some other function that will turn the code into text.
Addendum:
If you want individual attributes pulled as well, you're going to have to write a more complex regex to pull that text out. For instance:
$regex2 = '/\<.(?<=(title))(\=\").(?=\")/';
Would pull out (I think... I'm still learning RegEx) any text between < and title=", assuming you had no other matching expressions before title. Again, this would be a pretty complicated regex process.
This cannot be done in an automated way. PHP cannot know which node attributes you want to omit. You'd either had to create some code that iterates over all attributes and textnodes which you can feed a map, defining when to use a node's content or you just pick what you want with XPath one by one.
An alternative would be to use XMLReader. It allows you to iterate over the entire document and define callbacks for the element names. This way, you can define what to do with what element. See
http://www.ibm.com/developerworks/library/x-pullparsingphp.html
My solution is a bit more complicate but it worked fine for me.
If you are sure that you have XHTML, you can simply consider the code as XML (but you have to put everything in a proper wrapping).
Then with XSLT you can define some basic templates that do what you need.

Categories