How to setup split test? - php

I want to create a way to test different layouts on a page to see which get more conversions.
For example. If I have 2 versions of a page and I send 50% to page A and 50% to page B and see which one converts more sales.
So I am thinking maybe use .htaccess to rewrite half to page A and the other half to page B.
But how can I do that with .htaccess is there a way? do I need to use PHP instead to do this?
Also if there is a better way to do this, or any cautions I should be aware of, please let me know.

Lots of ways to deal with it on your own code. If however you're already using Google Analytics and don't care to use javascript for the test, spare yourself a lot of trouble and look at http://www.google.com/websiteoptimizer/index.html
Update (Reconfine): Google website optimizer no longer exists, this has been replaced with "Google Analytics content experiments" https://developers.google.com/analytics/devguides/platform/experiments-overview

I would do that using php, following way:
After the user got to the default php file, i would store his browser data in a db table, and the active layout identifier (filename, row id, etc...).
Everytime the server gets a request from this user, it shows the page, mapped to him.
But! If you have two independent pages, i would only store how many people visited site one, and site two, and redirect them to page A, and to page B by a 50% division.

If you've got a supported database and are using PHP 5.2 or later, you can use a free split testing library called phpScenario, found at www.phpscenario.org
Then you write more or less something like this:
require_once 'scenario_setup.php'; // you write this
if (Scenario::IsControl('experimentname')) {
// read and output version 1
} else {
// read and output version 2
}
Then when you get to your conversion point (say, sign up):
require_once 'scenario_setup.php'; // same
Scenario::Complete('experimentname');
And to view the stats (probably on your admin page):
require_once 'scenario_setup.php'; // yup
Scenario::RenderXml('experimentname');

I think php will be very useful. For example, you can use rand or push a variable in a file :
$int = file_get_contents('var');
if ($int) {
$int++;
} else{
$int = 1;
}
if (($int % 2) == 0) {
header('Location: url1);
} else {
header('Location: url2);
}
file_put_contents ('var', $int);
With apache, you have to setup a load balancer : http://httpd.apache.org/docs/2.1/mod/mod_proxy_balancer.html

I would use php personally. Then you can save which page layout you chose for them as a session var making it easy to load that layout on each page refresh. You would probably also want to save into the database with their username (if they login) and if they visit later show them the same layout.

Related

Page updates while processing

I have a PHP script that can take a few minutes to be done. It's some search engine which executes a bunch of regex commands and retrieve the results to the user.
I start by displaying a "loading page" which does an AJAX call to the big processing method in my controller (let's call it 'P'). This method then returns a partial view and I just replace my "loading page" content with that partial view. It works fine.
Now what I would like to do is give the user some information about the process (and later on, some control over it), like how many results the script has already found. To achieve that, I do another AJAX call every 5 seconds which is supposed to retrieve the current number of results and display it in a simple html element. This call uses a method 'R' in the same controller as method 'P'.
Now the problem I have is that I'm not able to retrieve the correct current number of results. I tried 2 things :
Session variable ('file' driver) : in 'P' I first set a session variable 'v' to 0 and then update 'v' every time a new result is found. 'R' simply returns response()->json(session('v'))
Controller variable : same principle as above but I use a variable declared at the top of my controller.
The AJAX call to 'P' works in both cases, but everytime and in both cases it returns 0. If I send back 'v' at the end of the 'P' script, it has the correct value.
So to me it looks like 'R' can't access the actual current value of 'v', it only access some 'cached' version of it.
Does anyone have an idea about how I'm going to be able to achieve what I'd like to do? Is there another "cleaner" approach and/or what is wrong with mine?
Thank you, have a nice day!
__
Some pseudo-code to hopefully make it a bit more precise.
SearchController.php
function P() {
$i = 0;
session(['count' => $i]); // set session variable
$results = sqlQuery(); // get rows from DB
foreach ($results as $result) {
if (regexFunction($result))
$i++
session(['count' => $i]); // update session variable
}
return response()->json('a bunch of stuff');
}
function R() {
return response()->json(session('count')); // always returns 0
}
I would recommend a different approach here.
Read a bit more about flushing content here http://php.net/manual/en/ref.outcontrol.php and then use it.
Long story short in order to display the numbers of row processed with flushing you could just make a loop result and flush from time to time or at an exact number or rows, the need for the 5 seconds AJAX is gone. Small untested example :
$cnt = 0;
foreach($result as $key => $val) {
//do your processing here
if ($cnt % 100 == 0) {
//here echo smth for flushing, you can echo some javascript, tough not nice
echo "<script>showProcess({$cnt});</script>";
ob_flush();
}
}
// now render the proccessed full result
And in the showProcess javascript function make what you want... some jquery replace in a text or some graphical stuff...
Hopefully u are not using fast_cgi, beacause in order to activate output buffering you need to disable some important features.
I believe you have hit a wall with PHP limitations. PHP doesn't multithread, well. To achieve the level of interaction you are probably required to edit the session files directly, the path of which can be found in your session.save_path global through php_info(), and you can edit this path with session_save_path(String). Though this isn't recommended usage, do so at your own risk.
Alternatively use a JSON TXT file stored somewhere on your computer/server, identifying them in a similar manner to the session files.
You should store the current progress of the query to a file and also if the transaction has been interrupted by the user. a check should be performed on the status of the interrupt bit/boolean before continuing to iterate over the result set.
The issue arises when you consider concurrency, what if the boolean is edited just slightly before, or at the same time, as the count array? Perhaps you just keep updating the file with interrupts until the other script gets the message. This however is not an elegant solution.
Nor does this solution allow for concurrent queries being run by the same user. to counter this an additional check should be performed on the session file to determine if something is already running. An error should be flagged to notify the user.
Given the option, I would personally, rewrite the code in either JSP or ASP.NET
All in all this is a lot of work for an unreliable feature.

"Dynamic" rewrite with mod_rewrite and apache

I´ve a bit of a "strategic" problem with creating a nice mod_rewrite solution for a shop. The shop has different kind of pages:
Products (products.php)
Categories (category.php)
Content (content.php)
So the "default" URI´s look like this:
/products.php?id=2
/category.php?id=4
/content.php?id=5
The final result should be a URI´s that include the name of the page (product name, category name).
/chocholate-icecream -> product.php?id=2
/coffe-and-ice -> category.php?id=4
/imprint -> content.php?id=5
My problem now is, that I´ve different types of content which maps to different .php files. And I´m unable to determine to which .php file to route with mod_rewrite as long as I don´t use a cheat "like **/product/**chocolate-icrecream" so that I know that this URI is made for a product. But me and my customer don´t want that solution.
I´ve already started another try:
ALL requests which don´t match a physical file or folder are routed to a mapper.php file. This file looks in the database - I´ve an index with all products, categories etc. - and gives me the correct file.
The mapper then loads the content via CURL and shows it to the user
Basically I thought this was a nice idea but there are so many problems with session handling, , post data, php based redirects (header: ...) with CURL that I really plan to cancel this way etc. etc.
So my question is:
Has anyone of you an idea or a pattern that helps me creating the "good looking" URI´s without using a complex CURL mapper?
Thanks a lot in advance,
Mike
UPDATE to "Include solution":
A good example for the "include problem":
A request for www.shop.com/cart is "rewritten" to "mapper.php". The "mapper.php" decides to include www.shop.com/shoppingcart.php.
shoppingcart.php uses smarty to display the cart. The view asks the $_SERVER variable, if the actual called file is "shoppingcart.php" to decide if the page should be shown in fullscreen mode or with additional columns.
In the "normal / direct" call $_SERVER['PHP_SELF'] would be "/shopping_cart.php" which will show the fullscreen version. Going over the mapper.php with the include option would give us $_SERVER['PHP_SELF']=='/mapper.php' which will give us the view with columns (what´s wrong).
You could do this simply by pointing them all to one page and then including the proper script based on the slug. For example, rewrite all requests like index.php?slug=chocolate-icrecream.
index.php
$resource = fetch_resource($slug);
if ($resource->slug == 'product')
{
include('products.php');
}
else if ($resource->type == 'category')
{
include('category.php');
}
else
{
include('content.php');
}
I don't understand why you don't want to structure your URLs like /product/chocolate-icrecream. That would be good semantic naming that is fairly consistent across the internet nowadays.

does a PHP page with includes get compiled and sent as one page?

I have a PHP page where the header and footer are PHP includes.
I want to know if there is any possibility of the includes loading asynchronously - or does PHP gather all the files required, compile them and send them as one file?
The reason I ask is that I've seen an interesting PHP app that seemed to keep the connection open and do things in sequence before closing the connection - I wondered if that's what happens with includes.
PHP version is 5.3.6
EDIT:
What I actually want is for the page to load all at once, to prevent my layout mashing as each bit loads. Sorry to any who misunderstood this
PHP does gather and compile them; everything goes to the browser as a single document. If you don't want this, you'll have to do something with XMLHTTPRequest on the frontend
Generally any output will be output as it is generated.
echo 'A';
sleep(1000);
echo 'B';
sleep(1000);
echo 'C';
This slowly outputs "ABC". Includes are included when they are encountered, the same way echo outputs anything at that specific point. It's all in order, never asynchronously.
A web server may buffer all output before sending any of it to the client. In the above example, you'd receive "ABC" all together after 2 seconds of nothing.
If your objective is to receive all the page at once you need to use ob_start() and ob_end_flush(). Do something like:
ob_start();
...
write all your outputs
...
ob_end_flush();
This will force the server to buffer the output until the whole page is prepared.
Good luck!
I use the following architecture when loading a page on my application:
index.php
<script src="path/to/js/lib/jslib.js" type="text/javascript"></script>
window.addEvent('load', function()
{
BuildPg(PgStatus); //PgStatus is a variable I use in a state machine to build different pages
});
<form>
<div id="DivPgTop"></div>
<div id="DivPgMiddle"></div>
<div id="DivPgBottom"></div>
</form>
This is the entire index.php
In my jslib.js I have functions like:
function BuildPg(Pg) {
BuildPgTop(Pg);
BuildPgMiddle(Pg);
BuildPgBottom(Pg);
}
function BuildPgTop(Pg) {
var Content="";
if (Pg == 1) {
Content = function_a(); // function_a builds the top of the page
else if (Pg == 2) {
Content = function_b();
etc...
}
document.getElementById("DivPgTop").innerHTML = Content; //here is where I load the top of the page
}
And I do the same for the other parts of the page Middle and Bottom.
Using this framework, if you changed my BuildPg() function to something like:
function BuildPg(Pg) {
BuildPgTop(Pg);
sleep(foo);
BuildPgMiddle(Pg);
sleep(bar);
BuildPgBottom(Pg);
}
Your user would experience the top of the page loading first, a delay, the middle of the page, another delay, and the bottom.
And if you change the order of the function calls you could even have the bottom of the page load first, then the middle and the top.
I hope this makes sense. Good luck!
PHP sends a single document. What you want to do is achieved with something called AJAX (http://en.wikipedia.org/wiki/Ajax_%28programming%29)
Basically you write some JavaScript code that uses XMLHTTPRequest object to connect to the server and download some extra info.

How to store search result?

I am working on my personal site, where I want to store my customers recent search result limited to that particular session.
I am using PHP platform and Javascripts.
Here is an example of what I am exactly looking at :
It stores your previously searched domain name for that particular session so that user can make decision by comparing those results.
Thanks.
EDIT- Well Thanks for all of your answers and suggestions.
But If you have noticed
above example
It looks like some kind of script loading a new content on the same page without refreshing it and keeping previous search content <div> as it is.
How to achieve this using javascripts or some sort of div layer ????
UPDATE START
This example uses page reload. If you want to do it without page reload, you can but you'll have to use AJAX to load new search results. But then, it's not a PHP question. I suggest looking at jquery library, as it makes it easy. Tutorials: http://docs.jquery.com/Tutorials and e.g. this one ( http://docs.jquery.com/Tutorials:Getting_Started_with_jQuery#Rate_me:_Using_Ajax ).
When loading data via AJAX, the page rendering result (in my example search.php) should return only HTML for results part, not whole HTML page. This is generally a first part of my tutorial (without session).
But I really think that AJAX in here is not really needed. Session is more reliable and allows access to your page from older / mobile browsers where not always JS works correctly.
UPDATE END
Ok then. Let's try the simple tutorial then. Sorry if too simple, but I don't know your exact level.
PHP has mechanism called sessions. In reality they are just bytes stored on server. Server knows which session is for each client by reading session cookie from client browser.
Not every page uses sessions (not every page needs it, and session uses server space, even if only temporarily), session is not enabled by default. To turn on session you use command
<?php session_start(); ?>
In most cases this is either run by PHP framework you use, or put near the top of your site. Session is definitely needed if you want to authenticate user somehow. Or in your case :)
To access session you can use superglobal $_SESSION variable (superglobal means that you can access it anywhere). It's an array, so session element will be e.g. $_SESSION['search'] etc.
As example, let's assume that your page looks like that
<html>
...
<form action="search.php" method="post">
Search: <input type="text" name="searchQuery" />
<input type="submit" value="Search" />
</form>
...
</html>
this very form will send user search to file named search.php. It can be the same file where the form resides - in simplest case when you put both your code and HTML in one file. Beginners often use this schema, although it's not advisable as result is a mess and hard to further change.
In search.php then, you'll use similar code:
<?php
if (!empty($_POST['searchQuery'])) //we have a new search
{
$result = do_search($_POST['searchQuery']);
}
?>
Then, somewhere below you'll display your search result ($result variable). do_search() function is your search mechanism, I guess you have it somewhere. You may have it not 'wrapped' in a function, then I advise to create it like that, it's much more useful.
function do_search($searchQuery)
{
...
return $result;
}
mind it, the above code doesn't use sessions yet. Let's add saving previous search results in session. The code may then look like that:
<?php
session_start(); //Starting session
//let's create session variable used to store results
if (!isset($_SESSION['searches']))
$_SESSION['searches'] = array();
if (!empty($_POST['searchQuery'])) //we have a new search
{
if (isset($_SESSION['searches'][$_POST['searchQuery']]) //User already searched on this value, delete previous result from sesion
{
unset($_SESSION['searches'][$_POST['searchQuery']]);
}
$result = do_search($_POST['searchQuery']);
//Let's add new search on the begining of session array to make iterations easier.
$result = array($_POST['searchQuery'] => $result); //convert result to same format as session table
$_SESSION['searches'] = array_merge($result, $_SESSION['searches']);
}
?>
In display you'll now not iterate on $result variable as before, but instead you will do something like
foreach ($_SESSION['searches'] as $query => $result)
{
...//display of single result
}
I haven't tested following code and it's not a full program. Parts to display result and to do actual search are not described but I guess you have them already prepared. Also, this is only one possible approach of countless possibilities. But I hope this helps :)
Possible modification - now I always perform search, even if user already searched on this term. You may want to receive the result from cache without second search. Then the code will look like
if (isset($_SESSION['searches'][$_POST['searchQuery']]) //User already searched on this value
{
$result = $_SESSION['searches'][$_POST['searchQuery']];
unset($_SESSION['searches'][$_POST['searchQuery']]);
}
else
{
$result = do_search($_POST['searchQuery']);
}
For more in-depth information about sessions and some other constructs used in my example I suggest PHP manual
http://pl.php.net/manual/en/book.session.php
and various tutorials over the network. Or you can add a comment here :)
Put this code near the beginning of your script(s):
if (!isset($_SESSION['previous_searches']) || !is_array($_SESSION['previous_searches'])) {
$_SESSION['previous_searches'] = array();
}
[edit]
This code snippet checks if if there is already an array with prevous searches and if not it will be created.
[/edit]
Then when the user hits the search page put this code in the receiving script of the search:
$_SESSION['previous_searches'][] = $_GET['what_ever_your_search_value_might_be'];
[edit]
This code snippet adds the current search value to the and of the array with previous search values
[/edit]
Now you have all previous search values in $_SESSION['previous_searches']
If your website is a web application where you never reload the page nor change the page, you can keep it JavaScript in a global store (declare at top level something like var StoredSearch = []; and use it). If not, then use $_SESSION to store this and AJAX to save/load searches from JavaScript to PHP.

PHP: re-parse entire page before serving?

At the end of a page, if something occurs, it needs to be cleared, then the entire page needs to be re-parsed before serving to the client. I was going to echo out a javascript to refresh the page, but that will make them load the page and then reload it...I was wondering if there was a way to just tell the php engine to go back to the beginning and re-parse the entire page?
Thanks!
I will try to explain the problem more clearly but it is complicated and I am a terrible communicator. I on the page that lists products I am giving users the option to select fields to narrow the results. The system remembers this so they don't have to keep selected them. If they narrow a category like metal color and then go to a category that metal color is irrelevant like crystal figurines it will not show any results because none will match the metal color chosen. To generate the query to pull the products from the data-base is very complicated because different categories have different requirements to find the correct products. so once the query is generated I want to test it against mysql_num_rows() and if there is no results clear out the users choices and start over.
You're being a little vague, but if you're merely talking about reparsing the output, you could do that using output buffering.
I'm not entirely clear what the issue is, but couldn't you decide what is to be shown before creating the HTML, and then send the right thing the first time?
To generate the query to pull the products from the data-base is very complicated because different categories have different requirements to find the correct products. so once the query is generated I want to test it against mysql_num_rows() and if there is no results clear out the users choices and start over.
In that case, just put the query inside a function that returns the result, check the row count, and if it's zero clear the filters and call that function a second time.
Output buffering (ob_start and ob_clean), combined with separating the functionality at hand into a separate file and eval()'ing that should do the trick.
Oh, and recent PHP versions actually have a goto statement... although I'll always deny mentioning anything about it. :-)
I think you're going about it a little bit off.
What you should do to reparse the page is to redirect the user to the page again, using
header('Location: thepagefile.php');
however if you actually would like to reparse the file without creating a new page, you could also just include the file again:
include thepagefile.php
But you'd probably get the same result. If you want to actually parse the output of the page you'd do something like:
ob_start(); // this is at the very top of the code/page
// all the code goes here
$output = ob_get_clean();
eval($output); // WTF?
but that actually makes no sense, but I hope it helps.
I'd actually like to know what the real problem you're trying to solve really is.
I think your looking for something like this:
<?php
ob_start(); //we start output buffering, this means nothing is send to the browser
//We do some code stuff
$time = microtime();
echo "Hai \n"; //Note taht mixing logic and output in real life
echo $time; // is terribly practice
echo "\n bai"; //I do it here purely for the example
if(/*some condition */){
$anErrorHappened = true;
}
if($anEroorHappened === true){
//Load the output in a var if you need it
//Otherwise don't
$output = ob_get_clean();
//Do other code stuff
//I.E. send an error page
include('errorPage.html');
}
else{
ob_end_flush(); //Send everything the script has echo()'d, print()'ed and send to the browser in any other way (I.E. readfile(), header() etc.)
}
?>

Categories