View previous topic :: View next topic |
Author |
Message |
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Tue Oct 04, 2011 8:05 pm Post subject: Endless loop while trying to compile a template |
|
|
Hi,
I'm afraid but I think that topic is gonna last a while - at least the problem seems really random to me. I can hardly reproduce it at all. Anyways. I'll dive right into it:
Scenario:
In the past weeks I primarily developed on my local machine (Win7, PHP5.2.8 on an XAMPP). Therefore I updated Smarty (3.0 -> 3.1) only locally at first. That worked more or less smoothly and in the end I got it running successfully.
Now I decided to update a semi-productive system with the so-far working state from my local machine. And that's when the fun began.
You know, I use Smarty for all backend files. So, I was able to open the index page of the backend (very simple template). However, opening another more complex backend page (that includes another template using {include file="filename.tpl"}) crashed Smarty. All I could see was the (correct) content of my header.tpl and then some weird var_dump-like output of the Smarty object instead of the content of my index.tpl (the body of the page). And that output was gigantic! Maybe it's even an endless loop - I dont know. My browser was about to crash, so I hit "stop".
Then I started to narrow down the problem. I deleted everything in the outer template except {include file="filename.tpl"} (relative path, both templates are in the same folder). And I deleted everything in the inner template except "hello world". The weird var_dump-output was still there.
Then I began to remove the $smarty->assign()'s in the original .php-file. I was able to remove all assignments that dealt with simple values (strings, numbers, booleans) while keeping the error. So, what was left was 1 assignment of a quite large array of objects. After removing the assignment of this array, the templates were displayed correctly.
Then I restored the deleted code in all files (the php and the 2 templates) - and against all odds, everything was working fine!
Then I deleted the contents of templates_c and everything was back to "normal" (i.e. the error with the var_dump-output came back).
My guess
Therefore my guess is that Smarty is somehow unable to compile the templates when there is a {include} in the template's code. I observed a similar behavior as described above in other templates (that also included other templates). So maybe you could have a look at compiling {include}'s?
As I said, it's really hard to reproduce and I'm far from being able to provide sample code. But maybe I described the problem in sufficient detail, so you can still have a look at the piece code that might be the culprit.
That'd be great! Because the bug somehow puts me in a delicate position (I could revert to 3.0 but then I wouldnt be able to receive any updates of Smarty anymore...)
Best regards
PS: In the meantime I tried the very latest revision from the SVN (rev4354). Without success.
PPS: I just want to stress that it seems to be sufficient to remove the assign() of the big array in order to make the templates work.
In case of an error, the compiled template for the index.tpl is not generated fully. Instead, I find a file called "wrt4e8b6948e7a31" in templates_c.
After removing the assign of the array, the template is compiled correctly (now named "...some characters....file.index.tpl.php").
The content of the two generated files is almost the same, except for some random-character-strings in the head of the files (e.g. in "'unifunc' => 'content_4e8b6948e5aeb'").
In case it helps I uploaded a zip containing both compiled files (the correct and the broken one): http://www57.zippyshare.com/v/79871858/file.html I have sent the PW for the zip to u.tews via PM - I hope that's ok |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 8:20 am Post subject: |
|
|
Good morning
still working on narrowing down the problem. Now I think {include} is not important. At least I was able to reproduce the error with just 1 template containing "bla". So it's not about the template.
So, basically the browser crashes because somehow the Smarty object is var_dump'ed while compiling the template. And since the Smarty object has got that huge array, the var_dump takes forever (or is actually endless). The array is huge because it contains objects that have properties that contain objects themselves that contain....and so on, you know There are actually also some recursions within that structure (var_dump prints "RECURSION"), so it's really big and definitely not var_dump'able
I am really wondering why the Smarty object is printed at all. Did you change something like that in 3.1.x? 3.0 was fine, as I said.
Maybe something with the output buffer (ob_start/ob_get)?
Or some left developer debug output?
The weird thing is, that locally it works perfectly. Btw, the server is running Apache/2.2.3 (Debian) PHP/5.2.8-0.dotdeb.1 with Suhosin-Patch. I'm not sure, but I vaguely remember some problems with the Suhosin patch (with some other scripts). So maybe there is a problem with Smarty and that patch? Do you have such an environment that you could use for testing purposes? |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 8:44 am Post subject: |
|
|
Sorry for posting again, just wanna keep you up2date
I significantly reduced the number of objects in the array (by deleting contents in the DB). Now I get
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 103574794 bytes) in /var/...my path.../inc/globalFunctions.inc.php on line 31
That line is one of my own escape methods
Code: | function out($content, $placeholderContent=null) {
// --- Insert placeholders if given
if(count(func_get_args())>2 || !empty($placeholderContent)) {
$functionArguments = func_get_args();
$content = call_user_func_array("sprintf", $functionArguments);
}
// htmlspecialchars cannot handle arrays -> replace with indicator that an array has been provided to this method
if(is_array($content))
$content = "[array provided]";
// Encode html relevant characters
return htmlspecialchars($content, ENT_QUOTES, "UTF-8");
} |
This function is also registered as modifier "out" (for {$myVar|out}).
So I var_dump'ed $content in this function to see when it's called with what parameters. Surprisingly, it was called a lot! It seemed like it is processing also Smarty properties and objects....dont know.
Maybe there is a name collision? Did you introduce a function called "out" recently? That would explain why the Smarty object is being printed at all... |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Wed Oct 05, 2011 2:47 pm Post subject: |
|
|
just a hunch: please check your ->assign() calls and make sure their return values are not processed in any way. For a quicker test, comment out all "return $this;" in Smarty_Internal_Templatebase.php _________________ Twitter |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 3:05 pm Post subject: |
|
|
Thanks!
But I'm not aware of using the return value of $smarty->assign()....didnt even know that it would make sense at some point. I quickly checked my code with a regex and it seems I'm using it only like "$smarty->assign(...)".
However I'd still like to do your quick test. However I couldnt find any "return $this;" in smarty_internal_templatebase.php. Only stuff like "return $this->$property_name;" and so on.
Could you give me a line number so I can see what you mean?
In case that doesnt help, do you have another idea? I'm willing to try basically anything - I really need this fixed, you know |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 3:11 pm Post subject: |
|
|
Not sure if it helps, but I actually dont use Smarty directly but rather as an extended sub-class "MySmarty". Maybe I'm using it the wrong way?
This is the constructor of the class:
Code: | /**
* Constructor of MySmarty
*
* This method also tries to set the $template_dir by considering $templateDir. Templates referenced by a relative path have to be in that directory.
* If not set the templates have to be referenced by absolute paths.
*
* You can also fetch files outside of $template_dir (e.g. in case you don't want to specify $module) using display("file: ....myfile.ext").
* See http://www.smarty.net/manual/en/template.resources.php for more details.
*
* @param string|Folder $templateDir The path to the folder of the templates. If not provided, only templates referenced by absolute paths can be fetched
*/
public function __construct($templateDir=null) {
parent::__construct();
// Smarty settings
$this->setForceCompile(false); // See http://www.smarty.net/manual/en/variable.force.compile.php
$this->setCompileCheck(Smarty::COMPILECHECK_ON); // See http://www.smarty.net/manual/en/variable.compile.check.php
$this->setDebugging(false); // If true, shows a JS popup debug console
$this->error_reporting = E_ALL ^ E_NOTICE; // Report all errors except E_NOTICE (e.g. thrown for undefined template tags)
// Directories (no exceptions because exceptions might be displayed using a template, too)
$this->setCompileDir(EXTERNAL_LIBS_PATH . "smarty" . DIRECTORY_SEPARATOR . "templates_c");
if(!is_writeable($this->getCompileDir())) {
echo "Smarty: compile_dir not writeable: " . out($this->getCompileDir());
exit;
}
$this->setConfigDir(EXTERNAL_LIBS_PATH . "smarty" . DIRECTORY_SEPARATOR . "configs");
if(!is_writeable($this->getConfigDir(0))) {
echo "Smarty: compile_dir not writeable: " . out($this->getConfigDir(0));
exit;
}
$this->setCacheDir(EXTERNAL_LIBS_PATH . "smarty" . DIRECTORY_SEPARATOR . "cache");
if(!is_writeable($this->getCacheDir())) {
echo "Smarty: compile_dir not writeable: " . out($this->getCacheDir());
exit;
}
// Look for template directory
if($templateDir!==null) {
if($templateDir instanceof Folder)
$templateDir = $templateDir->getPath();
// Check directory (no exceptions because exceptions might be displayed using a template, too)
if(!file_exists($templateDir)) {
echo "Smarty: Current template_dir does not exist: " . out($templateDir);
exit;
}
elseif(!is_readable($templateDir)) {
echo "Smarty: Current template_dir not readable: " . out($templateDir);
exit;
}
else
$this->setTemplateDir($templateDir);
}
// Register own modifiers
$this->registerPlugin("modifier", "out", "out");
$this->registerPlugin("modifier", "outHTML", "outHTML");
$this->registerPlugin("modifier", "info", array("Tools", "info"));
$this->registerPlugin("modifier", "absolutizeImgSrc", array("Tools", "absolutizeImgSrc"));
// Assign default variables
$this->assignDefaultTplVars();
}
/**
* Assigns some default template variables that should be available in all templates
*
* @return MySmarty Returns the current object
*/
public function assignDefaultTplVars() {
// Register the $myAccount object
$this->assign("myAccount", Account::getMyAccountObject());
// Workaround since Smarty doesnt support static calls (yet)
$this->assign("serverInstallationCompleted", ServerCheck::installationCompleted());
//Assign current skins dir as Smarty var
$this->assign("frontendSkinWebPath", Skin::getFrontendSkin()->getWebPath());
$this->assign("backendSkinWebPath", Skin::getBackendSkin()->getWebPath());
return $this;
} |
|
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Wed Oct 05, 2011 3:37 pm Post subject: |
|
|
Globe
Quote: | just a hunch: please check your ->assign() calls and make sure their return values are not processed in any way. For a quicker test, comment out all "return $this;" in Smarty_Internal_Templatebase.php |
Should have been:
comment out all "return $this;" in Smarty_Internal_Data.php
Before you then retry delete all existing files in the cache_dir and compile_dir folder. |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Wed Oct 05, 2011 3:54 pm Post subject: |
|
|
See? I told ya I needed to eat before getting back to Smarty! _________________ Twitter |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 4:05 pm Post subject: |
|
|
Haha, no hurry
But I'm sorry, the error remains. I cleared templates_c. |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Wed Oct 05, 2011 4:23 pm Post subject: |
|
|
have you removed "return $this;" from Smarty_Internal_Data.php? _________________ Twitter |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Wed Oct 05, 2011 4:43 pm Post subject: |
|
|
Yes, sure. Commented all "return $this"'s out. Then cleared templates_c and hit reload. Same thing.
Edit: Also removed the "return (string) $this" from Smarty_Variable::__toString(). |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Thu Oct 06, 2011 10:19 am Post subject: |
|
|
So, do you have any idea how to fix it? So far the only option I have is downgrading Smarty to 3.0x....but that cannot be it I guess :/ |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Thu Oct 06, 2011 10:29 am Post subject: |
|
|
can you identify where that memory limit exceeded error is happening? (Stack trace or something?) _________________ Twitter |
|
Back to top |
|
Mastershrimp Smarty Regular
Joined: 21 Dec 2009 Posts: 53
|
Posted: Thu Oct 06, 2011 10:34 am Post subject: |
|
|
Yeah, kinda at least. During my experiments with different templates I saw that the memory limit exceeded in one of my output functions. I use them all the time to mask HTML and so on. I also registered them as modifier. But as I said earlier, I reproduced the error just with a template containing "hello world" (no code, no modifiers, no nothing). So it's not about the template I guess. Rather sth with the compiling or so....no idea.
The affected function was:
Code: | function out($content, $placeholderContent=null) {
// --- Insert placeholders if given
if($placeholderContent !== null && count(func_get_args())>=2) {
$functionArguments = func_get_args();
$content = call_user_func_array("sprintf", $functionArguments);
}
// htmlspecialchars cannot handle arrays -> replace with indicator that an array has been provided to this method
if(is_array($content))
$content = "[array provided]";
// Encode html relevant characters
return htmlspecialchars($content, ENT_QUOTES, "UTF-8");
} |
The last line (return htmlspecialchars($content, ENT_QUOTES, "UTF-8");) is the one where the memory limit exceeded last time I saw the error message.
It's really weird. Some templates have that giant output (mentioned above) so I cancel the loading of the page. Other templates terminate quickly with "Memory limit exceeded" at that line mentioned above.
I really cannot figure out the cause. It seems very deep down in the code...Maybe something about the changes regarding the UTF8-compatibility of Smarty?
Edit: When I figured out that "out()" is causing problems, I var_dump'ed $content and looked at the result. Somehow the Smarty object ended up being printed (among other stuff of course)....so again, somehow Smarty is being printed (leading to the giant output in the one case and the memory limit in the other) |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Thu Oct 06, 2011 10:43 am Post subject: |
|
|
well, I'm pretty sure this is not a compiler-problem. This has got to do with the data you've assign()ed. did you throw the $smarty object into the assign()ed array? _________________ Twitter |
|
Back to top |
|
|