Browser detection using Zend Framework or Javascript - php

I am creating an application that requires the ability to upload large files. I have chosen to use the FormData object as using this I can report back to the user the progress.
Not surprisingly IE doesn't support this so I am having to fall back to Flash. What is the best way of detecting for IE 7/8/9+ using Zend Framework? I am loading in the other assets as per needed via the indexAction method in each controller. For example:
public function indexAction()
{
$this->view->stepnumber = 1;
$this->view->stepintro = 'Upload your photo.';
$this->view->headScript()->appendFile($this->view->baseUrl().'/assets/js/fileuploader.js');
}
Now, in one of my pages I have already done some form of browser detection (for some canvas work):
public function indexAction()
{
$u_agent = $_SERVER['HTTP_USER_AGENT'];
$this->view->stepnumber = 5;
$this->view->stepintro = 'Select your cut out detail.';
if(preg_match('/MSIE/i', $u_agent)) {
$this->view->headScript()->appendFile($this->view->baseUrl().'/assets/js/excanvas.js');
} else {
$this->view->headScript()->appendFile($this->view->baseUrl().'/assets/js/mootools/mootools-canvas-lib/mcl-min.js');
}
$this->view->headScript()->appendFile($this->view->baseUrl().'/assets/js/frank/pentool.js');
$image = $this->uploadsDb->getImage();
$data = $this->nodedataDb->getNodedata($image->id);
$this->view->image = $image;
$this->view->nodeData = $data;
}
I am not too sold on this method though, I would rather check using Javascript as this would be more futureproof (I think). But how would I go about using Javasript within my ZF layout.phtml so I'm only loading the Javascript that I require? Cutting down on calls to the server.
Any help is much appreciated.
SOLUTION:
I have decided to use YepNope:
yepnope({
test : "FormData" in window,
yep : 'normal.js',
nope : 'flashupload.js'
});

if you're looking for a easy way to append css style sheets / javascript files for IE only browsers, you can use the conditional comments argument, as such:
For any file besides css stylesheets:
$this->view->headLink()->appendFile($this->view->baseUrl() . '/media/js/core.js', 'text/javascript', array('conditional' => 'IE');
Note the array('conditional' => 'IE') argument.
For appending stylesheet files, the function arguments are a little different:
$this->view->headLink()->appendStylesheet($this->view->baseUrl() . '/media/css/core.css', 'all', 'IE');
http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.headstyle

you can add a javascript in case the feature is not available (i am using jquery for short syntax);
if(typeof featureA == "undefined"){
$("<script/>").attr({
"src" : "/assets/featurea.js",
"type": "text/javascript"
}).appendTo($("head").eq(0));
}
you can use the same for other features so you don't have to download'em all.

Related

setting iframe ID via fancybox2 to allow webdriver switchTo()->frame(id)

I'm using fancybox2 to create iframes but I can't see a way of setting the ID of the iframe that gets created, which is preventing me from using php-webdriver and selenium to test the contents of the iframe.
Simplified version of the code:
iframe
<script>
$(document).ready(function() {
$(".various").fancybox()
});
</script>
Which works, but using Chrome's inspector, the iframe was (this time) generated with an ID of
fancybox-frame1443817733402, which appears to be random. This means when I try to use php-webdriver to switch to this frame (having clicked the link to create the iframe), I can't predict the frame's ID to pass in:
$frame_id = 'fancybox-frame1443817733402'; // can't predict this in advance
$driver->switchTo()->frame($frame_id);
The iframe is always generated with a class of fancybox-iframe but calls to
$iframe = $driver->findElement(WebDriverBy::class("fancybox-iframe"))
return nothing.
I've also tried using fancybox2's afterLoad callback to try explicitly setting the iframe's ID before trying to switch to the frame by this ID, but that also fails (I think because current is an object, not an element?)
$(".various").fancybox({
afterLoad: function(current, previous) {
//console.log(current);
current.attr('id', 'rob');
}});
Is there a way of explicitly setting the iframe's ID so that I can switch to it via selenium/webdriver? Or is there a simpler way of doing this?
I don't know about setting the frame id here, but you can switch to a frame via xpath (such as //frame):
protected WebElement gotoIframeByXpath(final String iframeXpath) {
if (driver.findElements(By.xpath(iframeXpath)).size() > 0) { // find elements so an exception isn't thrown if not found
WebElement contentFrame = driver.findElement(By.xpath(iframeXpath));
driver.switchTo().frame(contentFrame);
return contentFrame;
} else {
System.out.println("Unable to find " + iframeXpath);
}
return null;
}
For anyone interested, following #EGHM's answer above, this is how I did it.
// this also works & is a little simpler
//$iframes = $driver->findElements(WebDriverBy::tagName('iframe'));
$iframes = $driver->findElements(WebDriverBy::xPath('//*[starts-with(#id,"fancybox-frame")]'));
$id = $iframes[0]->getAttribute('id');
$driver->switchTo()->frame($id);
echo $driver->getPageSource();

cakephp specify Theme for an Element in Controller

In cakephp, how do we specify which theme to use for an Element. I am initializing View object in Controller. I need to pass the element content as ajax response.
Controller :
$view = new View($this);
$view->layout = 'theme2';
$view->theme = 'newNav';
foreach($ctps as $ctpName)
{
$ctp[] = $view->element($ctpName);
}
At first I thought of accessing it as
$ctp[] = $view->element('../Themed/new/Elements/'.$ctpName);
But it obviously does not take care about element's directory. As some of the elements are in app/View/Elements and some are in app/ViewThemed/new/Elements/ directory.
Please suggest.
As per Arilia's suggestion, I am now trying
$this->viewClass = "Theme";
$this->viewPath = 'Elements';
$view = new View($this);
$view->theme = "new";
$view->layout = "theme";
$ctp = $view->element('userprofile');
echo json_encode($ctp);
die;
I am making an ajax call to this code. and it returns
"Element Not Found: Elements/userprofile.ctp"
what I was trying to develop was to render the basic page at first so that it can be cached. and then with the ajax call fetch the parts of UI that are session dependent and then replace the respective elements on browser.
To implement this, I tried fetching cakephp elements in controller, json encoding them and echoing them back. The code above though it worked for a normal dynamic page, it did not work for ajax calls. Cakephp somehow misbehaved here.
Now, as a better alternative, I have moved the code to View itself and I am echoing the json encoded from there. and as expected it is working well. Code is as
app/View/Themed/new/Elements/get_ctps.ctp :
<?php
foreach($ctps as $ctpName)
{
$ctp[] = $view->element($ctpName);
}
echo json_encode($ctp);
die;
?>
Its not a usual case. However, it might be helpful for someone.

Can I send raw keyboard input using Mink and Selenium2?

I am using Behat and Mink with the Selenium2 driver, and I'm trying to type directly into a form field (simulating raw keyboard input), instead of using the fillField() function.
This is what I'm trying:
$element = $this->getSession()->getPage()->find('css', '#questionName');
$element->focus();
$element->keyPress('a');
// also tried this, with no success
// $element->keyDown('a');
// $element->keyUp('a');
There is an <input type="text" id="questionName"> element on the page. It correctly receives the focus, but does not respond to any of the simulated keyboard input.
Is it possible to simulate raw keyboard input like this?
What am I doing wrong?
There seems to be a lot of posts complaining about keyPress not working as intended and some drivers don't support it at all. e.g.:
Goutte - Keyboard manipulations are not supported by Behat\Mink\Driver\GoutteDriver
The Selenium driver in particular uses a custom js library to run it's commands, however it doesn't seem to work. I've tried using both the $this->getSession()->getDriver()->keyPress() and the $element->getPress() without luck.
https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L815
https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2/syn.js
What is interesting is that there are no unit tests for the keyPress event in the Selenium2 code base yet (so I assume it's currently in development).
So, for the moment, an adequate solution is to use the javascript emulation of key events from Is it possible to simulate key press events programmatically? (see this for an alternative if you're not using jQuery) and Behat Mink's evaluateScript function.
If you're using straight PHPUnit to test:
$key = 'a';
$script = "jQuery.event.trigger({ type : 'keypress', which : '" . $key . "' });";
$this->getSession()->evaluateScript($script);
Or if you're using Cucumber, add this to your FeatureContext.php file you can add this function:
/**
* #Given /^(?:|I ) manually press "([^"]*)"$/
*/
public function manuallyPress($key)
{
$script = "jQuery.event.trigger({ type : 'keypress', which : '" . $key . "' });";
$this->getSession()->evaluateScript($script);
}
And use it in your feature file like this:
Given I manually press "a"
As for using the javascript as the solution, some of the drivers use javascript to perform the required keyPress. E.g.:
https://github.com/Behat/MinkZombieDriver/blob/master/src/Behat/Mink/Driver/ZombieDriver.php#L819
I'm using Mink with Zombie.js and as it does not catching keyboard events natively, I both listen to focusout and keyup jQuery events.
$('form[name="order"]').find('input[id$="quantity"],input[id$="price"]').bind('keyup focusout', function(){
// [...] update order price
});
I has solved the problem for me but I didn't try it with Selenium2.
The easiest answer I have found is to trigger the key event in javascript and write a specific behat step to send the js to the browser and trigger it.
We have been using YUI so we use the YUI event simulate but jquery or native js handles it. The concept is what matters. It's the best solution I've found until the native behat support is there.
hope this helps.
public function press_key_in_the_ousupsub_editor($keys, $fieldlocator) {
// NodeElement.keyPress simply doesn't work.
if (!$this->running_javascript()) {
throw new coding_exception('Selecting text requires javascript.');
}
// We delegate to behat_form_field class, it will
// guess the type properly.
$field = behat_field_manager::get_form_field_from_label($fieldlocator, $this);
if (!method_exists($field, 'get_value')) {
throw new coding_exception('Field does not support the get_value function.');
}
$editorid = $this->find_field($fieldlocator)->getAttribute('id');
// Get query values for the range.
$js = '
function TriggerKeyPressBehat() {
// http://www.wfimc.org/public/js/yui/3.4.1/docs/event/simulate.html
YUI().use(\'node-event-simulate\', function(Y) {
var id = "'.$editorid.'";
var node = Y.one("#" + id + "editable");
node.focus();
var keyEvent = "keypress";
if (Y.UA.webkit || Y.UA.ie) {
keyEvent = "keydown";
}
// Key code (up arrow) for the keyboard shortcut which triggers this button:
var keys = ['.$keys.'];
for(var i=0; i<keys.length;i++) {
node.simulate(keyEvent, { charCode: keys[i] });
}
});
}
TriggerKeyPressBehat();';
$this->getSession()->executeScript($js);
}

Retrieving Information from MySQL via PHP to AS3

I am currently doing a tutorial which was found on TutsPlus.
This tutorial was to save information from AS3 to MySQL via PHP and then retrieve this information.
So far, it works. I Can enter a username and score, which saves to the database. There is one problem though, I would like to be able to display ALL the names and scores in a table, instead of having to search for a name and then finding the score for that specific user.
The code in which the information is saved (which works), is below.
package {
import flash.display.*;
import flash.events.*;
import flash.net.*;
public class register extends MovieClip {
public function register ():void {
register_button.buttonMode = true;
register_button.addEventListener(MouseEvent.MOUSE_DOWN, checkForm);
username_text.text = "";
userbio_text.text = "";
}
public function checkForm (e:MouseEvent):void {
if (username_text.text != "" && userbio_text.text != "") {
sendForm();
} else {
result_text.text = "PLEASE ENTER A NAME";
}
}
public function sendForm ():void {
/*
we use the URLVariables class to store our php variables
*/
var phpVars:URLVariables = new URLVariables();
phpVars.username = username_text.text;
phpVars.userbio = userbio_text.text;
/*
we use the URLRequest method to get the address of our php file and attach the php vars.
*/
var urlRequest:URLRequest = new URLRequest("localhost/php/register.php");
/*
the POST method is used here so we can use php's $_POST function in order to recieve our php variables.
*/
urlRequest.method = URLRequestMethod.POST;
/*
this attaches our php variables to the url request
*/
urlRequest.data = phpVars;
/*
we use the URLLoader class to send the request URLVariables to the php file
*/
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
/*
runs the function once the php file has spoken to flash
*/
urlLoader.addEventListener(Event.COMPLETE, showResult);
/*
we send the request to the php file
*/
urlLoader.load(urlRequest);
}
/*
function to show result
*/
public function showResult (e:Event):void {
result_text.text = "" + e.target.data.result_message;
}
}
}
From here, I can go to another application and search the users name, and then displays that users score. Code below:
package actions {
import flash.display.MovieClip;
import flash.events.*;
import flash.net.*;
import flash.text.*;
public class main extends MovieClip {
public function main ():void {
submit_button.buttonMode = true;
submit_button.addEventListener(MouseEvent.MOUSE_DOWN, checkLogin);
username.text = "";
}
public function checkLogin (e:MouseEvent):void {
if (username.text == "") {
username.text = "Enter your username";
}
else {
processLogin();
}
}
public function processLogin ():void {
var phpVars:URLVariables = new URLVariables();
var phpFileRequest:URLRequest = new URLRequest("http://xx.xx.xx.uk/~bf93fv/Source%202/php/controlpanel.php");
phpFileRequest.method = URLRequestMethod.POST;
phpFileRequest.data = phpVars;
var phpLoader:URLLoader = new URLLoader();
phpLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
phpLoader.addEventListener(Event.COMPLETE, showResult);
phpVars.systemCall = "checkLogin";
phpVars.username = username.text;
phpLoader.load(phpFileRequest);
}
public function showResult (event:Event):void {
result_text.autoSize = TextFieldAutoSize.LEFT;
result_text.text = "" + event.target.data.systemResult;
}
}
}
The controlpanel.php file, which displays the username and score individually is below:
<?php
include_once "connect.php";
$username = $_POST['username'];
if ($_POST['systemCall'] == "checkLogin") {
$sql = "SELECT * FROM users WHERE username='$username'";
$query = mysql_query($sql);
$login_counter = mysql_num_rows($query);
if ($login_counter > 0) {
while ($data = mysql_fetch_array($query)) {
$userbio = $data["user_bio"];
print "systemResult=$username Scored $userbio";
}
}
else {
print "systemResult=The login details dont match our records.";
}
}
?>
Does anybody know any easy way in order to view ALL the information from the database into a table?
There are few things you might want to improve in your PHP code (your AS3 is better).
Use PDO instead of the functions that work with particular DBMS. The reason to this is that it is portable (to an extend). Say, if you wanted to ever move the database from MySQL to Postgres, you'd had to rewrite less of your code, then you would have to otherwise. PDO also provides some means of sanitizing the input. It's not bullet proof - still better then nothing. PDO is considered the "good practice", so you would learn to write the good code right away instead of making that journey from writing newby-style code at first and then discovering how to actually do it properly. It might be just a little bit more verbose if you are thinking about a very primitive task such as a single select, but as soon as your task becomes just a little bit more complex it becomes all worth the time.
In your SQL queries make a general rule never to use select *, unless for testing / debugging. That's sort of laziness that in the end will cost you a lot of problems. By doing so you will make it very difficult to maintain your code later, effectively transforming it into "write once - run away" kind of thing. Again, as a simple proof of concept it is OK, - long-term solution - bad. If you are still blur on what I'm trying to say: list all column names explicitly.
Using include / require and their _once family is a bad idea as a long-term solution. Again, OK for a simple test - bad in the long run. Good programs are written in functions / classes and use __autoload() or a framework that uses the ability to load classes automatically. This makes larger applications more manageable, easier to navigate and understand then the web of includes.
You must sanitize input from the user of your web application, that is don't do $_POST['key']. At least write the function that will both check that the key exists and that it is of an expected format.
Now, your actual problem, sending the data.
You can just send the raw SQL output you get in PHP - will spare your server the problem of re-encoding all of it. Works in the very simple cases, but it becomes more complex with more complex tasks. This is also uncommon to do, so you will find that people will not know how to handle that. (No technical restriction, it is just really a historical artefact).
There are a bunch of popular formats that can be digested by variety of applications, not necessary Flash. Those include XML, JSON, Protobuf. There are also some more particular to PHP like the one produced from serialize(). I'd urge you to stick to JSON if you go down this route. XML might be a more mature technology, but JSON has a benefit of the basic type system built in (while in XML it is yet another layer on top of it, which is, beside other things is not implemented in Flash - I'm talking about XSL).
There's AMF (ActionScript Message Format) - it is ideal for Flash. PHP also knows very well how to produce it (there are several popular implementations out there). This format is a lot more compact compared to JSON or XML. It has more expressive power (can describe circular dependencies, many-to-many relationships, has a procedure for introducing custom types, custom [de]serialization routines). It is also self-describing, unless you used custom serialization routine. This is the best option if you aren't planning on moving your application to JavaScript later, because JavaScript has problems consuming binary data. Parsing this format would not be possible there.
Protobuf is a viable option too. This is a data exchange format designed by Google. It is similar in spirit to AMF, however it may not be self-describing. It relies on the application to know how to produced custom objects from it. It has, however, a form, that can be parsed in JavaScript (although you'd lose the the compactness benefit).
Your ActionScript code: If you opt for AMF, you'd need to look into NetConnection class. I'd advise you to take a look in AMFPHP project - it also has examples. Alternatively, Zend Framework has Zend_Amf library to be used for that purpose. But using the entire framework may be overwhelming at start.
If you go with XML - then there's a built-in XML class, there are millions of examples on the web on how to use it.
If you go with JSON, then since not so long ago there's a built-in class for that too. But before there was one, there were several libraries to parse it.
There used to be a project on GoogleCode for Protobuf support in Flash, but it required quite a bit of acquittance and manual labour to get going.
Finally, index of things mentioned here:
http://php.net/manual/en/book.pdo.php - PDO
http://php.net/manual/en/function.json-encode.php - JSON in PHP
http://php.net/manual/en/book.dom.php - XML in PHP (There is no agreement on which XML library is better if PHP is considered. I'd probably stick to this, but ymmv).
http://www.silexlabs.org/amfphp/ - AMF in PHP
http://framework.zend.com/manual/1.12/en/zend.amf.html Zend_Amf library
http://code.google.com/p/protobuf-actionscript3/ Protobuf in ActionScript
https://github.com/drslump/Protobuf-PHP PHP Protobuf (sorry, never used this one, but looks fine)
http://www.blooddy.by/en/crypto/ for older versions of Flash player - this library has the best JSON decoder I know of.
The best way is (I think) to use XML.
On the PHP side, the script output an XML document with all the users :
$sql = "SELECT * FROM users "; // add order statement if needed
$query = mysql_query($sql);
$login_counter = mysql_num_rows($query);
$xml = array('<?xml version="1.0" encoding="UTF-8"?><users>');
if ($login_counter > 0) {
while ($data = mysql_fetch_array($query)) {
$xml[] = '<user name="'.$data['username'].'" bio="'.$data["user_bio"].'" />';
}
}
else {
// do nothing
// you will handle it on the flash side by checking the length of user nodes list
}
$xml[] = '</users>';
header('Content-Type:text/xml');
die(implode('', $xml));
This will output an XML document :
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user name="..." bio="..." />
<user name="..." bio="..." />
[...]
</users>
(There are class on PHP like SimpleXML to deal with XML in a cleaner way)
AS Side :
You can easily browse / display the data on the flash side with the help of the XML / XMLList class
Just adapt the URLLoaderDataFormat to TEXT and convert the data to XML in the complete event handler :
var xml:XML = new XML(event.target.data);
Then iterate the user elements to display them :
var users:XMLList = xml.user;
var user:XML;
for (user in users) {
trace('name->' + user.attribute('name') );
trace('bio->' + user.attribute('bio') );
}

CakePHP: Action runs twice, for no good reason

I have a strange problem with my cake (cake_1.2.0.7296-rc2).
My start()-action runs twice, under certain circumstances, even though only one request is made.
The triggers seem to be :
- loading an object like: $this->Questionnaire->read(null, $questionnaire_id);
- accessing $this-data
If I disable the call to loadAvertisement() from the start()-action, this does not happen.
If I disable the two calls inside loadAdvertisement():
$questionnaire = $this->Questionnaire->read(null, $questionnaire_id);
$question = $this->Questionnaire->Question->read(null, $question_id);
... then it doesn't happen either.
Why?
See my code below, the Controller is "questionnaires_controller".
function checkValidQuestionnaire($id)
{
$this->layout = 'questionnaire_frontend_layout';
if (!$id)
{
$id = $this->Session->read('Questionnaire.id');
}
if ($id)
{
$this->data = $this->Questionnaire->read(null, $id);
//echo "from ".$questionnaire['Questionnaire']['validFrom']." ".date("y.m.d");
//echo " - to ".$questionnaire['Questionnaire']['validTo']." ".date("y.m.d");
if ($this->data['Questionnaire']['isPublished'] != 1
//|| $this->data['Questionnaire']['validTo'] < date("y.m.d")
//|| $this->data['Questionnaire']['validTo'] < date("y.m.d")
)
{
$id = 0;
$this->flash(__('Ungültiges Quiz. Weiter zum Archiv...', true), array('action'=>'archive'));
}
}
else
{
$this->flash(__('Invalid Questionnaire', true), array('action'=>'intro'));
}
return $id;
}
function start($id = null) {
$this->log("start");
$id = $this->checkValidQuestionnaire($id);
//$questionnaire = $this->Questionnaire->read(null, $id);
$this->set('questionnaire', $this->data);
// reset flow-controlling session vars
$this->Session->write('Questionnaire',array('id' => $id));
$this->Session->write('Questionnaire'.$id.'currQuestion', null);
$this->Session->write('Questionnaire'.$id.'lastAnsweredQuestion', null);
$this->Session->write('Questionnaire'.$id.'correctAnswersNum', null);
$this->loadAdvertisement($id, 0);
$this->Session->write('Questionnaire'.$id.'previewMode', $this->params['named']['preview_mode']);
if (!$this->Session->read('Questionnaire'.$id.'previewMode'))
{
$questionnaire['Questionnaire']['participiantStartCount']++;
$this->Questionnaire->save($questionnaire);
}
}
function loadAdvertisement($questionnaire_id, $question_id)
{
//$questionnaire = array();
$questionnaire = $this->Questionnaire->read(null, $questionnaire_id);
//$question = array();
$question = $this->Questionnaire->Question->read(null, $question_id);
if (isset($question['Question']['advertisement_id']) && $question['Question']['advertisement_id'] > 0)
{
$this->set('advertisement', $this->Questionnaire->Question->Advertisement->read(null, $question['Question']['advertisement_id']));
}
else if (isset($questionnaire['Questionnaire']['advertisement_id']) && $questionnaire['Questionnaire']['advertisement_id'] > 0)
{
$this->set('advertisement', $this->Questionnaire->Question->Advertisement->read(null, $questionnaire['Questionnaire']['advertisement_id']));
}
}
I really don't understand this... it don't think it's meant to be this way.
Any help would be greatly appreciated! :)
Regards,
Stu
Check your layout for non-existent links, for example a misconfigured link to favicon.ico will cause the controller action to be triggered for a second time. Make sure favicon.ico points towards the webroot rather than the local directory, or else requests will be generated for /controller/action/favicon.ico rather than /favicon.ico - and thus trigger your action.
This can also happen with images, stylesheets and javascript includes.
To counter check the $id is an int, then check to ensure $id exists as a primary key in the database before progressing on to any functionality.
For me it was a JS issue.
Take care of wrap function with jQuery that re-execute JS in wrapped content!
You might want to try and find out where it comes from using the debug_print_backtrace() function. (http://nl.php.net/manual/en/function.debug-print-backtrace.php
Had the same problem, with a certain action randomly running 2-3 times. I tracked down two causes:
Firefox add-on Yslow was set to load automatically from it's Preferences, causing pages to reload when using F5 (not when loading the page from the browser's address bar and pressing Enter).
I had a faulty css style declaration within the options of a $html->link(); in some cases it would end up as background-image: url('');, which caused a rerun also. Setting the style for the link to background-image: none; when no image was available fixed things for me.
Hope this helps. I know this is quite an old post, but as it comes up pretty high in Google when searching for this problem, I thought it might help others by still posting.
Good luck
Jeroen den Haan
I had a problem like this last week.
Two possible reasons
Faulty routes (DO check your routes configuration)
Faulty AppController. I add loads of stuff into AppController, especially to beforeFilter() and beforeRender() so you might want to check those out also.
One more thing, are where are you setting the Questioneer.id in your Session? Perhaps that's the problem?
Yes, it occurs when there is a broken link in the web page. Each browser deals with it variously (Firefox calls it 2x). I tested it, there is no difference in CakePHP v1.3 and v2.2.1. To find out who the culprit is, add this line to the code, and then open the second generated file in you www folder:
file_put_contents("log-" . date("Hms") . ".txt", $this->params['pass'] ); // CakePHP v1.3
file_put_contents("log-" . date("Hms") . ".txt", $this->request['pass'] ); //CakePHP v2.2.1
PS: First I blame jQuery for it. But in the end it was forgotten image for AJAX loading in 3rd part script.
I had the same problem in chrome, I disabled my 'HTML Validator' add on. Which was loading the page twice
I was having a similar issue, the problem seemed to be isolated to case-insensitivity on the endpoint.
ie:
http://server/Questionnaires/loadAvertisement -vs-
http://server/questionnaires/loadavertisement
When calling the proper-cased endpoint, the method ran once -whereas the lower-cased ran twice. The problem was occurring sporadically -happening on one controller, but not on another (essentially the same logic, no additional components etc.). I couldn't confirm, but believe the fault to be of the browser -not the CakePHP itself.
My workaround was assuring that every endpoint link was proper-cased. To go even further, I added common case-variants to the Route's configuration:
app/config/routes.php
<?php
// other routes..
$instructions = ['controller'=>'Questionnaires','action'=>'loadAvertisement'];
Router::connect('/questionnaires/loadavertisement', $instructions);
Router::connect('/QUESTIONNARIES/LOADADVERTISEMENT', $instructions);
// ..etc
If you miss <something>, for example a View, Cake will trigger a missing <something> error and it will try to render its Error View. Therefore, AppController will be called twice. If you resolve the missing issue, AppController is called once.

Categories