I'm having trouble with using PHP code on my pages, within my body content area. I've searched tirelessly on this site, Drupal's site, and other sites in general, so I apologize if the answer is on this site somewhere, but I can't find it and I need help.
We have a lot of info we reuse throughout our site that I'd like to store in a PHP file as variables. We do this on our site now, but I'm rewriting our whole site to use Drupal. So, for example, we sell software, and I'd like a variable for each of our product URLs for various 'add to cart' buttons on the site. I don't want to have to hardcode the product URL into each link, but rather to seta PHP variable that I can call on any drupal page.
I cannot get anything to work; I've read about several suggestions but none work. I've tried setting the variables as their own block, then calling them from within a page when I create a new page. I can echo the variables on the pages but only within the block they are inside, I cannot call them and get them to echo from other blocks or content areas. I've tried using the global keyword (as per one suggestion) but that didn't work for me.
I hope this makes sense. Other info? I'm using Drupal 6.x, I do have PHP code enabled when creating pages, I do have the PHP filter module enabled, I can get PHP code to render so I know it's working, it's just not working where I need it to be.
I should say (if it's not obvious just from reading this!) I am a Drupal newbie so if anyone can help and try to explain their suggestion as plainly as possible for me, I'd really appreciate it!
Thanks in advance.
EDIT 3/15/11
To try to explain further, I'll post some sample code. I haven't done this yet because there isn't much to show yet, and I thought it might confuse the issue even more.
So, I've made a Drupal 'page' which is for our software trial downloads. The PHP variables that I want to set are for our download links; I want to set them in one place so that if, in the future, the download link needs to change, I only have to do so in one spot. You see, we have download links on various site pages. The same is true of our 'buy now' links. Here is the page code:
<p>Try [product] free for 30 days.</p>
<!--<p>[token_custom_ewintry]</p>-->
<p><?php global $ewintry; ?>Download for Windows PC</p>
<p><?php global $emactry; ?>Download for Mac OS X</p>
<p><?php global $ebbtry; ?>Download for BlackBerry</p>
<?php
$ebbtryprint = variable_get("ebbtry", "default");
print $ebbtryprint;
?>
<p>Download for Windows Mobile</p>
<p><?php global $ipewlstorelink; ?>iPhone, iPad, iPod touch owners: Download [product] on the iTunes App Store. You'll be able to create 10 cards for free to try [product] before you buy!</p>
For this sample I've left in everything I've tried. You'll see my calls to global variables, which never worked. I have the global variables defined in a custom block that I created and placed in my 'content top' region. I learned that apparently nothing from that region is actually accesible to my page's body content, because the calls never worked.
I have a custom token that I made yesterday with the Tokens module; it never worked, but then I read on a different post that by default, tokens are available in the body content area, and I need a special filter. I've yet to find a filter, and so I am not sure this solution will ever work.
I have my call to variable_get. Now, this did work. I have variable_set defined within my template.php page. My value does print using the print call above in my code sample. However, I looked at this page this morning and I don't think that's the answer I need. Because now I'll have to call variable_get on all my pages before I can print anything, right? And that doesn't solve the problem where I wanted to only have to set everything in one place to call anywhere. I tried putting the variable_get call in my custom block, but again I can't access anything in 'content top' from my body content area. The variable_get call prints the value in 'content top' but then it will not re-print below that in the content area.
So maybe that code will help someone to help me. I am going to look in detail at CCK now, as that's the only other suggestion I haven't tried. Thanks in advance if anyone can help.
If you're trying to set a global variable, and then use it within a function/method block, you need to use the global keyword on import:
<?php
// For some reason, this sometimes gives me problems
$foo = 'test';
// So I do this instead, they are equivalent
$GLOBALS['bar'] = 'test';
echo "<p>Global <br/> foo: $foo <br/> bar: $bar</p>";
function globalTest() {
global $foo;
echo "<p>globalTest() <br/> foo: $foo <br/> bar: $bar</p>";
}
globalTest();
function globalBarTest() {
global $foo, $bar;
echo "<p>globalBarTest() <br/> foo: $foo <br/> bar: $bar</p>";
}
globalBarTest();
?>
In action: http://jfcoder.com/test/globals.php
Prints:
Global
foo: test
bar: test
globalTest()
foo: test
bar:
globalBarTest()
foo: test
bar: test
I have always gotten in the habit of setting a global variable using $GLOBALS, I never have any issues doing it this way.
I would caution, though, that setting globally scoped variables is considered harmful (or at least unnecessary), since they are so easy to accidentally overwrite somewhere else in your code (by you and/or someone else).
Your stated approach in the description sounds quite messy; you should be using a database and let Drupal abstract how you organize, set and get the data from the datastore, instead of editing your files and hardcoding some links and data into a PHP file. This is what I'm thinking reading your description, which may not be fair, but I thought I needed to mention it.
EDIT
In Drupal, you can set global variables in the default/settings.php page using variable_set(), and then use variable_get() to get the variable by name.
http://api.drupal.org/api/drupal/sites--default--default.settings.php/6
variable_set('foo','bar');
http://api.drupal.org/api/drupal/includes--theme.inc/function/template_preprocess/6
function yourtemplate_preprocess (&$variables) {
$vars['foo'] = variable_get('foo');
}
EDIT 2
Note the source for the variable_set() function:
<?php
function variable_set($name, $value) {
global $conf;
$serialized_value = serialize($value);
db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name);
if (!db_affected_rows()) {
#db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value);
}
cache_clear_all('variables', 'cache');
$conf[$name] = $value;
}
?>
EDIT
Ok, here is what you can do:
/drupal-root/htdocs/sites/settings.php
Open the settings.php file and at the bottom, set your PHP variables using the $GLOBALS global variables, as so:
$GLOBALS['test1_variable'] = 'test 1 variable';
And then in your template (with the PHP Input Format selected):
<?php
echo "<p>This is my {$GLOBALS['test1_variable']}.</p>";
?>
Or...
<p>This is my short tag <?=$GLOBALS['test1_variable'];?>.</p>
And you should see your variable printed out on the page from the template code. Note the curly braces surrounding the $GLOBALS variable.
If you want to provide additional info that should go with some nodes, you should use CCK to create a content type, that has all the additional infos. With styling inside a template, you can archive almost anything.
If CCK is not siutable (in most cases, it is exactly what you want), you need to implement a _preprocess_ function. This would look like
function yourtemplate_preprocess_page(&$variables) {
$vars['my_custom_var'] = "hello"; //anything can go here
}
Now you have a $my_custom_var in your page-template file available.
Be sure to make yourself familiar with the template system of Drupal (if you haven't already).
It sounds like you are looking for the token_filter module.
My problem is that it isn't ready (in token module) for D7 yet.
Related
I am using wordpress for a web site. I am using snippets (my own custom php code) to fetch data from a database and echo that data onto my web site.
if($_GET['commentID'] && is_numeric($_GET['commentID'])){
$comment_id=$_GET['commentID'];
$sql="SELECT comments FROM database WHERE commentID=$comment_id";
$result=$database->get_results($sql);
echo "<dl><dt>Comments:</dt>";
foreach($result as $item):
echo "<dd>".$item->comment."</dd>";
endforeach;
echo "</dl>";
}
This specific page reads an ID from the URL and shows all comments related to that ID. In most cases, these comments are texts. But some comments should be able to point to other pages on my web site.
For example, I would like to be able to input into the comment-field in the database:
This is a magnificent comment. You should also check out this other section for more information
where getURLtoSectionPage() is a function I have declared in my functions.php to provide the static URLs to each section of my home page in order to prevent broken links if I change my URL pattern in the future.
I do not want to do this by using eval(), and I have not been able to accomplish this by using output buffers either. I would be grateful for any hints as to how I can get this working as safely and cleanly as possible. I do not wish to execute any custom php code, only make function calls to my already existing functions which validates input parameters.
Update:
Thanks for your replies. I have been thinking of this problem a lot, and spent the evening experimenting, and I have come up with the following solution.
My SQL "shortcode":
This is a magnificent comment. You should also check out this other section for more information
My php snippet in wordpress:
ob_start();
// All my code that echo content to my page comes here
// Retrieve ID from url
// Echo all page contents
// Finished generating page contents
$entire_page=ob_get_clean();
replaceInternalLinks($entire_page);
PHP function in my functions.php in wordpress
if(!function_exists("replaceInternalLinks")){
function replaceInternalLinks($reference){
mb_ereg_search_init($reference,"\[custom_func:([^\]]*):([^\]]*)\]");
if(mb_ereg_search()){
$matches = mb_ereg_search_getregs(); //get first result
do{
if($matches[1]=="getURLtoSectionPage" && is_numeric($matches[2])){
$reference=str_replace($matches[0],getURLtoSectionPage($matches[2]),$reference);
}else{
echo "Help! An unvalid function has been inserted into my tables. Have I been hacked?";
}
$matches = mb_ereg_search_regs();//get next result
}while($matches);
}
echo $reference;
}
}
This way I can decide which functions it is possible to call via the shortcode format and can validate that only integer references can be used.
I am safe now?
Don't store the code in the database, store the ID, then process it when you need to. BTW, I'm assuming you really need it to be dynamic, and you can't just store the final URL.
So, I'd change your example comment-field text to something like:
This is a magnificent comment. You should also check out this other section for more information
Then, when you need to display that text, do something like a regular expression search-replace on 'href="#comment-([0-9]+)"', calling your getURLtoSectionPage() function at that point.
Does that make sense?
I do not want to do this by using eval(), and I have not been able to accomplish this by using output buffers either. I would be grateful for any hints as to how I can get this working as safely and cleanly as possible. I do not wish to execute any custom php code, only make function calls to my already existing functions which validates input parameters.
Eval is a terrible approach, as is allowing people to submit raw PHP at all. It's highly error-prone and the results of an error could be catastrophic (and that's without even considering the possibly that code designed by a malicious attacker gets submitted).
You need to use something custom. Possibly something inspired by BBCode.
To put my question into context, I'm working on an entirely static website where 'post' pages are created by myself manually - there's no CMS behind it. Each page will require a <pre> <code> block to display code as text in a styled block. This could be very few - several which is why I'm trying to do this for ease.
Here's what I've done -
function outputCode($code) {
return "<pre class='preBlock'><code class='codeBlock'>".htmlentities($code)."</code></pre>";
}
The code works as expected and produces an expected outcome when it's able to grab code. My idea is to somehow wrap the code for the code block with this function and echo it out for the effect, fewer lines and better readability.
As I'm literally just creating pages as they're needed, is there even a way to create the needed code blocks with such function to avoid having to manually repeat all the code for each code block? Cheers!
EDIT:
I was previously using this function and it was working great as I was pulling code from .txt documents in a directory and storing the code for code blocks in a variable with file_get_contents(). However, now, I'm trying to get the function to work by manually inputting the code into the function.
Well. Wrapping the function input in ' ' completely slipped my mind! It works just fine now!
If I understand correctly, you want to re-use your outputCode function in several different PHP files, corresponding to posts. If yes, you could put this 1 function in its own file, called outputcode.php for example, and then do
include "outputcode.php";
in every post/PHP file that needs to re-use this function. This will pull in the code, from the one common/shared file, for use in each post/PHP file that needs it. Or maybe I'm misreading your last paragraph :(
I have built a custom CMS. Recently, I added the ability to create pages dynamically. I used CKEditor for the content of these pages.
I would also like to run some php functions that may be included in the content of the page stored in mysql.
I DO NOT want to store actual PHP code in the database, but rather function names perhaps. For example, in a page stored in the database I may have.
<?php //begin output
hello world!
check out this latest news article.
news($type, $id);
//end output
?>
What is the best way to find and execute this existing function without using EVAL if its found in the output? I was thinking along the lines of wordpress style short codes. Maybe [[news(latest, 71]] ? Then have a function to find and execute these functions if they exist in my functions.php file. Not really sure the best way to go about this.
I'm not searching for any code answers, but more of a best practice for this type of scenario, especially one that is safest against possible injections.
I found a solution from digging around and finding this thread
How to create a Wordpress shortcode-style function in PHP
I am able to pass short codes like this in CKEditor
[[utube 1 video_id]]
Then, in my page that renders the code:
print shortcodify($page_content);
using this function:
function shortcodify($string){
return preg_replace_callback('#\[\[(.*?)\]\]#', function ($matches) {
$whitespace_explode = explode(" ", $matches[1]);
$fnName = array_shift($whitespace_explode);
return function_exists($fnName) ? call_user_func_array($fnName,$whitespace_explode) : $matches[0];
}, $string);
}
If the function name exist (utube) it will fire the function.
Only problem Im having at the moment is not matter where I place the [[shortcode]] in my editor, it always executes first.
For example, in CKEditor I put:
Hello world! Check out my latest video
[[utube 1 video_id]]
It will always put the text under the video instead of where it is in the document. I need to figure a way to have the short code execute in the order it is placed.
What's the best way to create a temporary variable inside a .phtml template while abiding by Magento's architecture?
Example
File: /template/catalog/product/view.phtml
<?php
$myVar = $_product->getAttributeText('color');
if ( empty($myVar) ) {
// does not exist
} else {
// show the attribute
}
?>
Beyond this expression $myVar isn't needed anywhere else.
Note: I'm not looking for alternative ways to write this code that avoid creating vars. For the sake of argument, assume a scenario where creating a temporary var is necessary.
What should $myVar be?
$myVar
$namespaced_myVar
$_myVar
Magento's registry pattern http://alanstorm.com/magento_registry_singleton_tutorial
Something else...
Looking for a "real world" solution more than a purist answer. How would you write this?
Answer
Combined between Ben's answer and this bit from Alan/Vinai's conversation https://twitter.com/VinaiKopp/status/225318270591442945 — this is how I'm going to write it:
If the anything more than basic logic is needed, I'll extend the class with new methods.
Otherwise, I'll create new vars in the local scope like so:
$mynamespace_myVar = 'xyz';
This is what I like about it:
The $mynamespace_ reminds me I created this and not Magento
It also makes it highly unlikely another developer overwrites my vars
This is what I don't like:
It's un-pure and potentially corruptible, but I probably only need this <5 times for an entire site so it's reasonably shielded.
Not using $_ to show the var is local to this template is not "the Magento way" but it makes the code more readable.
So my templates will mostly have code like this:
$gravdept_someNiceData = true;
Some history: https://stackoverflow.com/a/3955757/833795
Re 1, 2, & 3: Differentiating between these choices involves getting into "purist answer" territory, as they are all local variables.
Using the registry pattern is uncalled for, as the desired scope is stated to be local to the rendering of the template.
Based on your example, an appropriate construction in Magento might be:
<?php if ($_product->getColor()): ?>
<h2> I HAZ COLOR </h2>
<?php else: ?>
<h2> I NO HAZ COLOR </h2>
<?php endif ?>
If there is anything but the simplest test of return values it's appropriate to add this logic as a method of the block class (using a rewrite), as it is in fact view logic which you've mentioned should be local to this context only.
I want to define something like this in php:
$EL = "\n<br />\n";
and then use that variable as an "endline" marker all over my site, like this:
echo "Blah blah blah{$EL}";
How do I define $EL once (in only 1 file), include it on every page on my site, and not have to reference it using the (strangely backwards) global $EL; statement in every page function?
Most PHP sites should have a file (I call it a header) that you include on every single page of the site. If you put that first line of code in the header file, then include it like this on every page:
include 'header.php';
you won't have to use the global keyword or anything, the second line of code you wrote should work.
Edit: Oh sorry, that won't work inside functions... now I see your problem.
Edit #2: Ok, take my original advice with the header, but use a define() rather than a variable. Those work inside functions after being included.
Sounds like the job of a constant. See the function define().
Do this
define ('el','\n\<\br/>\n');
save it as el.php
then you can include any files you want to use, i.e
echo 'something'.el; // note I just add el at end of line or in front
Hope this help
NOTE please remove the '\' after < br since I had to put it in or it wont show br tag on the answer...
Are you using PHP5? If you define the __autoload() function and use a class with some constants, you can call them where you need them. The only aggravating thing about this is that you have to type something a little longer, like
MyClass::MY_CONST
The benefit is that if you ever decide to change the way that you handle new lines, you only have to change it in one place.
Of course, a possible negative is that you're calling including an extra function (__autoload()), running that function (when you reference the class), which then loads another file (your class file). That might be more overhead than it's worth.
If I may offer a suggestion, it would be avoiding this sort of echoing that requires echoing tags (like <br />). If you could set up something a little more template-esque, you could handle the nl's without having to explicitly type them. So instead of
echo "Blah Blah Blah\n<br />\n";
try:
<?php
if($condition) {
?>
<p>Blah blah blah
<br />
</p>
<?php
}
?>
It just seems to me like calling up classes or including variables within functions as well as out is a lot of work that doesn't need to be done, and, if at all possible, those sorts of situations are best avoided.
#svec yes this will, you just have to include the file inside the function also. This is how most of my software works.
function myFunc()
{
require 'config.php';
//Variables from config are available now.
}
Another option is to use an object with public static properties. I used to use $GLOBALS but most editors don't auto complete $GLOBALS. Also, un-instantiated classes are available everywhere (because you can instatiate everywhere without telling PHP you are going to use the class). Example:
<?php
class SITE {
public static $el;
}
SITE::$el = "\n<br />\n";
function Test() {
echo SITE::$el;
}
Test();
?>
This will output <br />
This is also easier to deal with than costants as you can put any type of value within the property (array, string, int, etc) whereas constants cannot contain arrays.
This was suggested to my by a user on the PhpEd forums.
svec, use a PHP framework. Just any - there's plenty of them out there.
This is the right way to do it. With framework you have single entry
point for your application, so defining site-wide variables is easy and
natural. Also you don't need to care about including header files nor
checking if user is logged in on every page - decent framework will do
it for you.
See:
Zend framework
CakePHP
Symfony
Kohana
Invest some time in learning one of them and it will pay back very soon.
You can use the auto_prepend_file directive to pre parse a file. Add the directive to your configuration, and point it to a file in your include path. In that file add your constants, global variables, functions or whatever you like.
So if your prepend file contains:
<?php
define('FOO', 'badger');
In another Php file you could access the constant:
echo 'this is my '. FOO;
You might consider using a framework to achieve this. Better still you can use
Include 'functions.php';
require('functions');
Doing OOP is another alternative
IIRC a common solution is a plain file that contains your declarations, that you include in every source file, something like 'constants.inc.php'. There you can define a bunch of application-wide variables that are then imported in every file.
Still, you have to provide the include directive in every single source file you use. I even saw some projects using this technique to provide localizations for several languages. I'd prefer the gettext way, but maybe this variant is easier to work with for the average user.
edit For your problem I recomment the use of $GLOBALS[], see Example #2 for details.
If that's still not applicable, I'd try to digg down PHP5 objects and create a static Singleton that provides needed static constants (http://www.developer.com/lang/php/article.php/3345121)
Sessions are going to be your best bet, if the data is user specific, else just use a conifg file.
config.php:
<?php
$EL = "\n<br />\n";
?>
Then on each page add
require 'config.php'
the you will be able to access $EL on that page.