I am trying to configure HTMLPurifier to only display external links as plain text. I used DisplayLinkURI option but it display all links as a plain text. is there any configuration for that? here is my code:
$mySite='mysite';
$externalSite='external';
require_once 'include/htmlpurifier/library/HTMLPurifier.auto.php';
$Config = HTMLPurifier_Config::createDefault();
$Config->set('AutoFormat.DisplayLinkURI', true);
$purifier = new HTMLPurifier($Config);
$mySite= $purifier->purify($mySite);
$externalSite=$purifier->purify($externalSite);
echo $mySite;
echo $externalSite;
The output is
<a>mysite</a> (http://www.mysite.com/)
<a>external</a> (http://www.external.com/)
I want the output to be like this:
mysite
<a>external</a> (http://www.external.com/)
Update:
I want to keep external links for images without change. I only need to convert hyperlinks to plain text.
I believe this is the one you're looking for
http://htmlpurifier.org/live/configdoc/plain.html#URI.DisableExternal
There's an option named URI.DisableExternal and AutoFormat.Linkify. Set them both to TRUE and see what happens.
http://htmlpurifier.org/live/configdoc/plain.html#URI.DisableExternal
http://htmlpurifier.org/live/configdoc/plain.html#AutoFormat.Linkify
And AutoFormat.DisplayLinkURI disables all the links. I suggest you use both the above instead of AutoFormat.DisplayLinkURI.
http://htmlpurifier.org/live/configdoc/plain.html#AutoFormat.DisplayLinkURI
Ok, I succeeded to add a custom injector to HTMLPurifier, here it is:
First, Create a "DisplayRemoteLinkURI.php" in "include\htmlpurifier\library\HTMLPurifier\Injector" and write this in it
<?php
class HTMLPurifier_Injector_DisplayRemoteLinkURI extends HTMLPurifier_Injector
{
public $name = 'DisplayRemoteLinkURI';
public $needed = array('a');
public function handleElement(&$token) {
}
public function handleEnd(&$token) {
if (isset($token->start->attr['href'])){
$url = $token->start->attr['href'];
if($this->is_remote($url)){
unset($token->start->attr['href']);
$token = array($token, new HTMLPurifier_Token_Text(" ($url)"));
}
} else {
// nothing to display
}
}
public function is_remote($path){
$urlvar = parse_url($path);
$remote_schemes = array("mailto");
$local_schemes = array("javascript");
if(in_array($urlvar["scheme"],$remote_schemes)){
return true;
}else if(in_array($urlvar["scheme"],$local_schemes)){
return false;
}else{
if(empty($urlvar["host"]) || $urlvar["host"]==$_SERVER["HTTP_HOST"]){
return false;
}else{
return true;
}
}
}
}
?>
And then create another file named "AutoFormat.DisplayRemoteLinkURI.txt" in "include\htmlpurifier\library\HTMLPurifier\ConfigSchema\schema" and add this :
AutoFormat.DisplayRemoteLinkURI
TYPE: bool
VERSION: 3.2.0
DEFAULT: false
--DESCRIPTION--
<p>
This directive turns on the in-text display of Remote URIs in <a> tags, and disables
those links. For example, example becomes
example (<a>http://example.com</a>).
</p>
--# vim: et sw=4 sts=4
After that, Add this line
require 'HTMLPurifier/Injector/DisplayRemoteLinkURI.php';
under
require 'HTMLPurifier/Injector/DisplayLinkURI.php';
in include\htmlpurifier\library\HTMLPurifier.includes.php
Then, Add this line
require_once $__dir . '/HTMLPurifier/Injector/DisplayRemoteLinkURI.php';
under
require_once $__dir . '/HTMLPurifier/Injector/DisplayLinkURI.php';
in include\htmlpurifier\library\HTMLPurifier.safe-includes.php
After these edits, if your files are at local, run cmd.exe and go to your php directory. Then run "include/HTMLPurifier/maintenance/generate-schema-cache.php" from php.exe.
Or if you want to do this via browser, rename your .htaccess file inside "include/HTMLPurifier/maintenance/" to something else for a while, then add this line inside "generate-schema-cache.php" on the first line after the <?php tag;
php_set_env("PHP_IS_CLI",true);
and then run this file from browser. After you see "Saving schema.. done!", rename your .htaccess file back.
Then in your script, use "AutoFormat.DisplayRemoteLinkURI" as config, and voila!
Note that the is_remote() function inside the first file I gave here might be not so good, and I couldn't find a script that checks if a link is remote or local, so you might alter it later if you need.
Related
I was wandering if it were possible to store a html schema page with special strings to replace with variable and how to do it.
In an external file, I would like to put the html structure of a product, let's call it schema.php:
<span id="{% id %}">{%= name %}</span>
<span>{%= imageURL() %}</span>
The example above is just a simpler example. In the external file, the html would be more complex. I know that if there were just few lines I could just echo them with a simple function but this is not the case.
In another file I have a class that handle products, let's call it class.php:
class Product {
//logic that is useless to post here.
public function imageURL() {
return "/some/url".$this->id."jpg";
}
}
In this class I would like to add a function that take the content from schema.php and then echo it in the public file for users.
I tried with file_get_contents() and file_put_contents() but it just doesn't work:
$path_to_file = 'data/prodotti/scheda.inc';
$file_contents = file_get_contents($path_to_file);
$file_contents = str_replace(
"{%= ",
"<?php echo $this->",
$file_contents
);
$file_contents = str_replace(
" }",
"; ?>",
$file_contents
);
file_put_contents($path_to_file, $file_contents);
is it possible to call schema.php page and print it with custom variables?
By "schema page" I think you mean "template" and yes, but the best way to do it is to use an existing templating engine such as Smarty or a Mustache implementation like https://github.com/bobthecow/mustache.php instead of implementing it yourself because of the risks of XSS, HTML-injection, and how you'll eventually want features like looping and conditionals.
you can do it normaly with php require func. without any strings to replace, if you just want to use that file as "template" then:
in schema.php:
<?php
echo'<span id="'.$id.'">'.$name.'</span>
<span>'.$imageURL.'</span>';
?>
in class.php:
<?php
class Product {
//logic that is useless to post here.
public function imageURL() {
return "/some/url".$this->id."jpg";
}
}
$imageURL = imageURL(); ?>
Index.php or whatever the main page that handles class.php and temp.php(schema)
<?php
//avoid undefined variables on errors
//in case that you don't check for values submitted
$id = 0;
$name = 0;
$imageURL = '';
//set vars values
$id = /*something*/;
$name = /*something 2*/;
$imageURL = /*something3*/;
//all date will be replaced is ready, oky nothing to wait for
require('path/to/schema.php');
Note: If you gets these data from user, then you should validate with if(isset()).
hope that helps,
I have a Book Now button on each page of my website. I would like to know which button is selected and don't really want to add 25+ blocks to the site to add the class manually. I can use Google Analytics if I can make the button unique (add an additional class based on the page URL). But I'm not a coder although I'm familiar with both PHP and jQuery.
Hye Michael, after reading your question i have tested your scenario on my local test drupal site. And it's really easy to achieve it. Here is a piece of PHP code you need to put into your block you created.
<?php
$url = current_path();
$class_from_url = explode("/", $url);
echo "<a href=[link_to_whatever] class='". $class_from_url[0] ."'>[Link Title]</a>";
?>
Make sure your "PHP filter" module is enabled which will allow you to select PHP code from "Text formats" under the block body.
For Drupal 7, the best way to accomplish your goal would be to copy the theme_button() function to your theme's template.php file and add some custom code to check the URL and add the class.
YOURTHEME_button($vars) {
$element = $variables ['element'];
$element ['#attributes']['type'] = 'submit';
element_set_attributes($element, array('id', 'name', 'value'));
$element ['#attributes']['class'][] = 'form-' . $element ['#button_type'];
if (!empty($element ['#attributes']['disabled'])) {
$element ['#attributes']['class'][] = 'form-button-disabled';
}
// Check URL to determine what button class to add
$button_class = null;
$current_path = base_path() . request_path();
switch ($current_path) {
'/form1':
$button_class = 'button-for-form1';
break;
'/form2':
$button_class = 'button-for-form2';
break;
}
if ($button_class !== null) {
$element ['#attributes']['class'][] = $button_class;
}
return '<input' . drupal_attributes($element ['#attributes']) . ' />';
}
Note that this method will add the class only for URLs that you explicitly specify, and it ignores any user-supplied parameters that might be included as part of the URL.
I want to ask the user to locate a folder on the (windows) commandline.
Usually you'll be able to use autocomplete with the [tab] key.
But not if I ask this from a phpscript.
I use this class:
<?php
class CLQuestion
{
protected $_awnser;
protected $_options;
protected $_question;
public function __construct($question, $options = array())
{
$this->_question = $question;
$this->_options = $options;
$this->askQuestion();
$this->waitForAwnser();
}
protected function askQuestion()
{
echo PHP_EOL . $this->_question . PHP_EOL;
}
protected function waitForAwnser()
{
while (true) {
$response = strtolower(trim(fgets(STDIN)));
// are options given?
if (empty($this->_options)) {
// no options given, so the response is our awnser
$this->_awnser = $response;
break;
} else if (!empty($this->_options) && in_array($response, $this->_options)) {
// options given and found in options
$this->_awnser = $response;
break;
} else {
// options given and not found.
echo PHP_EOL . 'Please use one of these options: ';
echo PHP_EOL . " " . implode(PHP_EOL . " ", $this->_options);
echo PHP_EOL;
continue;
}
}
}
public function getAwnser()
{
return $this->_awnser;
}
}
With this usage:
<?php
$question = new CLQuestion('Where is you folder located?');
$question->getAwnser(); // path typed
Windows CMD will give me a way to interact, but when i use the [tab] key, it does not autocomplete but it show a tab.
Am I able to activate path autocompletion in some way?
autocompletion is a feature of a windows shell prompt.
When you run an application like:
php script.php
this application gains control over STDIN and STDOUT and magic shell features like autocompletion will work no more until this app finishes.
This for example allows you to run one shell inside another.
If you need autocompletion in your script, you will need to implement it yourself. Instead of reading whole line with fgets(STDIN) you could read it char by char with fgetc(STDIN) and when the char will equal "\t" you would have to list files in current directory with php functions and check witch paths are matching to what user have written till now. So you will basically have to re-implement fgets adding magic autocompletion feature.
But instead of doing this and implementing your own shell I guess it would be far more better to make the folder location a script argument:
<?php
if(empty($argv[1])) die("usage: php script.php folderpath");
echo "your folder is located at:" . $argv[1];
So you could call it from windows shell like:
#php script.php
usage: php script.php folderpath
#php script.php foldername
your folder is located at: foldername
And then the autocompletion feature will work.
The Situation:
I have a Projects page with a content area and a sidebar. I want the sidebar to contain a dynamic list of projects. The content area has an div with the id "post".
I have a subfolder containing .php files corresponding to projects that contain html content about each project.
The Challenge:
I would like the sidebar to generate an unordered list based on the filenames of the php files (or if possible, an h1 element inside each php file).
When clicked, I would like each of the items in this unordered list to populate the div id "post" in the content area with the contents of the php file to which it corresponds.
Is this possible?
I know it would be easier with a CMS like Wordpress, but I want to know how to do it without an SQL database if possible. Keep in mind, I know almost nothing about PHP. I have stuck to html/css so far.
The Solution:
function getfiles($dir){
if(!is_dir($dir))
return false;
$dirhandle = opendir($dir);
$files = array();
while($entry = readdir($dirhandle)){
if($entry!='.' && $entry!='..' && !is_dir($dir.'/'.$entry))
$files[]=$entry;
}
return $files;
}
Returns an array of the files. There are three special entries in a directory that aren't files. . refers to the directory it's in. .. refers to the parent directory. Finally, there are other directories. So far as I know, everything else is a file.
And then:
function createlist($dir){
if(!$files=getfiles($dir))
return false;
?>
<script type="text/javascript" >
function getcontent(xthis) {
var httpRequest;
makeRequest(xthis.href);
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
return false;
}
httpRequest.onreadystatechange = putContents;
httpRequest.open('GET', url);
httpRequest.send();
}
function putContents() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
document.getElementById("post").innerHTML=httpRequest.responseText;
} else {
return false;
}
}
}
}
</script>
<?PHP
echo "<ul>\n";
foreach($files as $file){
echo "\t<li><a onclick=\"getcontent(this);return false;\" href=".$dir."/$file>$file</a></li>\n";
}
echo "</ul>";
return true;
}
Ajax functions courtesy of https://developer.mozilla.org/en/AJAX/Getting_Started.
Listing Files
# index.php
<?php
if( $files = glob('/path/to/directory/*.php') )
{
?>
<ul id="sidebar">
<?php
foreach( $files as $path_raw )
{
$file_raw = basename($path_raw);
$file_safe = htmlentities($file_raw);
$file_urlsafe = urlencode($file_raw);
?>
<li><a class="file-link" href="/post.php?file=<?php echo $file_urlsafe; ?>"><?php echo $file_safe; ?></a></li>
</ul>
<?php
}
To locate the files, we will want to use glob(). In this case, pass in a path to a directory (/path/to/directory) and a filename pattern (*.php) to find all '.php' files in the specified directory.
glob() returns an array, so we will need to iterate over the result using foreach.
Since we are providing an absolute path to the directory where the files are located, glob() will return an array of absolute paths, so we will need to use basename() to strip off the directory info and just get the filename.
Although unusual, it is possible for filenames to have unsafe characters in them, so we need to escape the values using urlencode() for URL strings (the href for the anchor tag) and htmlentities() otherwise (the text of the anchor tag).
Reading Files
The link in the unordered list references a file named post.php under the web server's document root.
# post.php
<?php
$basedir = '/path/to/directory';
if( empty($_GET['file']) )
{
// Handle error condition: no filename provided.
}
$file_raw = $_GET['file'];
$file_safe = basename($file_raw);
if( ! is_file($file_safe) )
{
// Handle error condition: file does not exist or is not a file.
}
elseif( ! is_readable($file_safe) )
{
// Handle error condition: file exists, but is not readable (probably permissions issue).
}
passthru($file_safe);
post.php Expects a $_GET value named file to be provided (taken care of by clicking on one of the links in the sidebar). It is important to note a couple of things:
Web browsers are capable of requesting any URL, so we cannot assume that the user arrived at post.php by clicking on a sidebar link, so we must check a few things:
The file value might be missing (we can check for this by using empty()).
The file value might have a different value than we were expecting (in this case, we will use basename() to ensure that we are dealing with a filename and not an injected path).
Even if the file value is valid, it might reference a path that is not actually a file, or it points to a file that the webserver cannot access (we check for these cases by using is_file() and is_readable(), respectively).
Finally, once we are sure that the file value points to a valid file, we send its contents to the web browser using passthru().
The Javascript
The only thing left to do is to use some Javascript so that clicking on one of the sidebar links displays the contents in the #post div. I will use jQuery here for brevity:
# index.php
(function($){
$(function(){
var post = $('#post');
$('#sidebar a.file-link').click(function( e ){
post.load($(this).attr('href'));
e.preventDefault();
});
});
})(jQuery);
This code leverages the .load() method, which executes an ajax call and replaces the selected element with the content from that request.
We use .click() to set the ajax call to only trigger when the user clicks on one of the links in the sidebar, and we determine which URL to go to by calling .attr() on the clicked link to extract its href attribute.
Note that we use the event's preventDefault method rather than returning false to avoid potential for unwanted side effects.
Can someone help me to establish using IRC URI Scheme for HTML Purifier 4.2.0? I can't seem to figure out how to configure or which files to modify so that purified html allows for irc:// links.
Is it possible I can simply modify configuration within the following code block?
require_once "htmlpurifier-4.2.0/library/HTMLPurifier.standalone.php";
$purifier_config = HTMLPurifier_Config::createDefault();
$purifier_config->set("HTML.Doctype", "XHTML 1.0 Strict");
$purifier = new HTMLPurifier($purifier_config);
Update:
I edited library/standalone/HTMLPurifier/ConfigSchema/schema.ser changing both instances of "4:nntp" to "3:irc" and found error:
Warning: Directory htmlpurifier-4.2.0/library/standalone/HTMLPurifier/DefinitionCache/Serializer/URI not writable, please chmod to 777
I believe this will help to establish support for IRC URI Scheme after making this change. I'll report back in a bit.
Hmm, after making it writable, no error appeared, but no results =\
HTML Purifier doesn't seem to have a native support for the IRC scheme. But: Have you tried something like this? Put this in /library/HTMLPurifier/URIScheme, or otherwise make sure that autoloading finds it:
class HTMLPurifier_URIScheme_irc extends HTMLPurifier_URIScheme {
public $default_port = 6667;
public $browsable = false;
public function validate(&$uri, $config, $context) {
if (parent::validate($uri, $config, $context) === false) {
return false;
}
if (!is_null($uri->path)) {
// get channel name
$uri->path = array_shift(explode('/', $uri->path));
}
$uri->userinfo = null;
$uri->query = null;
$uri->fragment = null;
return true;
}
}
...and change your configuration with...
$purifier->config->set(
'URI.AllowedSchemes',
array('irc' => true, /* ... other schemes here ... */)
);
That may not work out of the box, but I'm thinking that should be the right direction...