How to debug a PHP file that is being called by AJAX? - php

I have a php file for uploading a picture (it uploads the picture, creates its thumbnail and also adds watermark to the picture). The file is being called by AJAX.
It was working on on my localhost on Windows XP with WAMPSERVER 2.0. Now I have installed Windows Vista and suddenly it doesn't work properly (the picture gets uploaded but the thumbnail and watermark parts don't work).
I'm using exactly the same software to test the application on my local machine (WAMPSERVER 2.0) yet it doesn't work.
How to debug this file? Here's how it looks:
<?php
define('BASE_PATH', substr(dirname(dirname(__FILE__)), 0, -22));
// set the include path
set_include_path(BASE_PATH
. '/../../library'
. PATH_SEPARATOR
. BASE_PATH
. '/library'
. PATH_SEPARATOR
. get_include_path());
// autoload classes from the library
function __autoload($class) {
include str_replace('_', '/', $class) . '.php';
}
$configuration = new Zend_Config_Ini(BASE_PATH
. '/application'
. '/configs/application.ini',
'development');
$dbAdapter = Zend_Db::factory($configuration->database);
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);
function _getTable($table)
{
include BASE_PATH
. '/application/modules/default/models/'
. $table
. '.php';
return new $table();
}
$albums = _getTable('Albums');
$media = _getTable('Media');
if (false === empty($_FILES)) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$extension = end(explode('.', $_FILES['Filedata']['name']));
// insert temporary row into the database
$data = array();
$data['type'] = 'photo';
$data['type2'] = 'public';
$data['status'] = 'temporary';
$data['user_id'] = $_REQUEST['user_id'];
$paths = $media->add($data, $extension, $dbAdapter);
// save the photo
move_uploaded_file($tempFile,
BASE_PATH . '/public/' . $paths[0]);
// create a thumbnail
include BASE_PATH . '/library/My/PHPThumbnailer/ThumbLib.inc.php';
$thumb = PhpThumbFactory::create('/' . $paths[0]);
$thumb->adaptiveResize(85, 85);
$thumb->save(BASE_PATH . '/public/' . $paths[1]);
// add watermark to the bottom right corner
$pathToFullImage = BASE_PATH . '/public/' . $paths[0];
$size = getimagesize($pathToFullImage);
switch ($extension) {
case 'gif':
$im = imagecreatefromgif($pathToFullImage);
break;
case 'jpg':
$im = imagecreatefromjpeg($pathToFullImage);
break;
case 'png':
$im = imagecreatefrompng($pathToFullImage);
break;
}
if (false !== $im) {
$white = imagecolorallocate($im, 255, 255, 255);
$font = BASE_PATH . '/public/fonts/arial.ttf';
imagefttext($im,
13, // font size
0, // angle
$size[0] - 132, // x axis (top left is [0, 0])
$size[1] - 13, // y axis
$white,
$font,
'HunnyHive.com');
switch ($extension) {
case 'gif':
imagegif($im, $pathToFullImage);
break;
case 'jpg':
imagejpeg($im, $pathToFullImage, 100);
break;
case 'png':
imagepng($im, $pathToFullImage, 0);
break;
}
imagedestroy($im);
}
echo "1";
}

For generally debugging this, you should break the steps down into functions and test each part in turn.
With regard to Ajax debugging, you might like to try out Zend_Log_Writer_FirePHP. It's an extension for Firebug which reads extra data in headers sent by PHP, which means that the data in your response body doesn't contain debug output, and for things like images, can still be rendered.
Once you've installed FirePHP for Firebug, you can just write the following few lines:
$wFirebug = new Zend_Log_Writer_Firebug();
$firebug = new Zend_Log($wFirebug);
$firebug->info($myArray);
$firebug->info('Got to line 10');

When debugging anything that is related to AJAX I would recommend the following:
Ensure that the file is returning the correct data without any AJAX wrapper around it. Call the file directly with some sample data. Does it return what you require? Does it have syntax errors? This is the first thing you want to check and it will save you a ton of headache.
Ensure your Javascript is parsing the data correctly. Your JS may be expecting JSON but you're returning XML, or your returned data is not formatted the way you think, or you may need to evaluate your returned data in Javascript so it can actually be used. Try some console.log()'s to test what your data looks like.
Try something like Postbin which lets you send POST data. Ensure your POST data is correct and you're sending the right data to your script.

You could just create a simple form with a file input and just use that for easy testing.
That is the simplest way that I see, someone else may have something better in mind.

I find that when working with an action being called via AJAX in ZF, it's always a good idea to make sure that the action works without AJAX first. That is, make your first iteration of developing the feature result in going to a new page to represent the action you're making.
Once you know that your PHP code works, you can then begin to worry about making the AJAX stuff work. In my opinion, at least, being able to output Zend_Debug::dump() on variables when you view another page is a lot easier for initial development.
AJAX by design creates a layer of opacity which can makes it difficult to do this. It gets even harder if you're interfacing with, for instance, a jQuery plugin that requires formatted data that you're just not getting for some reason. So again, PHP first, AJAX second. It takes roughly two seconds in ZF to go from a PHP to an AJAX call, and vice versa.

The easiest solution would be to use FirePHP; install firebug + firephp addon for firefox and include the classes in your project.
(I keep the FirePHP library in /usr/share/php/ so I can include it easily in any project)
Then just do this:
require_once('/path/to/FirePHPCore/FirePHP.class.php');
$fp = FirePHP::getInstance(true);
$fp->log('you can put anything here, vars, objects, arrays, etc');
It will output the response in the FireBug console and is much better than polluting your code with echos and var_dumps when debugging ajax!

Make the AJAX request with a callback function, which checks the data returned (echo'd) from the PHP function. If the data echo'd is some pre-determined success string ("success"?) then all is well, if it's not that, have the callback function output whatever is output by the function in an alert or something.

Related

Embedding charts in the PDF using TCPDF library

I am working on a project in which a PDF file is to be generated.
I have used Google Chart API for generating different charts. I am using the TCPDF library for converting them into PDF but I am unable to embed these genearted graphs into the PDFs. I think TCPDF does not accept the contents written in the script tag. How can I overcome this problem?
I ran into the same problem except I was using FPDF.
At the end of the day, a PDF file contains static content, so Javascript is out of the question unfortunately. What I ended up doing:
I prepare the chart HTML + Javascript like always and write it to a HTML file in my temp directory. Then I use PhantomJS (http://phantomjs.org/) to create a screenshot of the page which I then include in my PDF (or anywhere, really).
The great thing: it works with ANY local HTML page. If you only have a URL, use file_get_contents() or cURL to retrieve its contents and write it to a local HTML file first.
The guts:
To start, download and extract phantomjs.exe to a directory your application can access. My example uses version 1.9.8 that I copied to lib/phantomjs in my application root.
I have a function that accepts a HTML file path as parameter and a set of PhantomJS options. I suggest adding it to a helper class.
function getHTMLImage($page, $options = array(), $js = null) {
// Prepare the PhantomJS directory that contains phantomjs.exe, e.g. lib or vendor
$phantomDir = $_SERVER['DOCUMENT_ROOT'] . '/lib/phantomjs/';
// Add the PhantomJS directory to the PATH
$origPath = str_replace('"', '', getenv('PATH'));
if (!in_array($phantomDir, explode('/', $origPath)))
putenv('PATH=' . $origPath . '/' . $phantomDir);
// PhantomJS requires a Javascript file to process the request. In case no Javascript processing file is given, use the default
if (is_null($js)) $js = $phantomDir . 'phantom.js';
// Prepare the PhantomJS call
$exec = 'phantomjs --ignore-ssl-errors=yes ' . $js . ' ' . escapeshellarg($page);
// Prepare the PhantomJS options, e.g. width and height
foreach ($options as $option) {
$exec .= ' ' . escapeshellarg($option);
}
// Call PhantomJS. To catch errors, call exec($exec . ' 2>&1', $output, $errorMsg);
exec($exec, $output);
// Decode and return the image data
return ($output ? base64_decode(reset($output)) : false);
}
The Javascript file (mine is called phantom.js and is placed in the same directory as phantomjs.exe):
args = require('system').args;
page = require('webpage').create();
// In this case, I expect these indexes to be the width and height of the chart
if (typeof args[2] !== undefined) {
page.viewportSize = {
width: args[2],
height: (typeof args[3] === undefined ? args[2] : args[3])
};
}
page.open(args[1], function() {
var base64 = page.renderBase64('png');
console.log(base64);
phantom.exit();
});
Call it like this:
// Make sure $width and $height are set, or exclude them altogether
$output = getHTMLImage($htmlPath, array($width, $height));
// Example output, you want to save the image and include it in your PDF file
header('Content-Type: image/png');
exit($output);

FileDrop.js & PHP resulting in empty $_FILES

JSFIDDLE
I'm using filedrop.js to create a file repository structure within my app. The above noted JSFIDDLE has all of the Javascript / jQuery / HTML and CSS code for this small module. While everything on the client end seems to be functioning properly (files can be DnD'd, progress bar acts correctly, console shows proper event triggers), the result on the server-side is always an empty $_FILES variable. My PHP (ajax.receiveFile.php) is as follows:
var_dump($_FILES);
ob_start();
$callback = &$_REQUEST['fd-callback'];
$job_id = &$_REQUEST['job_id'];
$subdir = &$_REQUEST['subdir'];
$j = loadJob($job_id);
$save_path = "D:\\JobFiles\\" . $j->gOrderNumber() . "\\" . $subdir . "\\";
if ( ($_FILES['fd-file']['size'] > 0) && is_uploaded_file($_FILES['fd-file']['tmp_name']) ) {
$name = $_FILES['fd-file']['name'];
if (move_uploaded_file($_FILES['fd-file']['tmp_name'], $save_path.$name)) {
$j->addAttachment($subdir,$name);
echo 'true';
} else {
echo 'false';
}
}
ob_end_flush();
FileDrop.js seems to be doing what it is supposed to do, as shown here:
I read here on SO that using the same element name over multiple input types of "file" can cause errors but I'm not sure that is the case here. I have double- and triple-checked the permissions on both the TEMP and TARGET upload folders, I have confirmed that all PHP variables are set as needed via visual inspection and PHPINFO(). The server config is PHP 5.4 on IIS7.
If anyone has any ideas on what else to look for, please contribute. Thanks!
This works for me:
file_put_contents('uploads/person/7.jpeg', fopen('php://input', 'r'));

Yii and Image upload YUSH

I have a problem that I simply don't know how or as a matter of fact what to solve. I'm using Yii and an extension called YUSH. This helps with folder structuring when uploading an image.
On my localhost everything works great. But now that I migrated to a live server, the filename still gets written to the database but a folder containing the uploaded file is not created. Thus only an image placeholder is displayed.
This isn't giving any error messages, so I really don't know how to fix it. My host has increased my mem_size in php.ini and I have checked all my error logs. Still nothing.
Here is my code:
$image = CUploadedFile::getInstance($l, 'path');
if ($image)
{
// Clean up the filename
$encName = md5($image->name . microtime()) . '.' . $image->extensionName;
$l->path = $encName;
}
$l->merchant_id_fk = $this->getMerchantRelation(Yii::app()->user->id);
switch ($l->validate()) {
// User validate Successfull
case TRUE:
if($l->save())
{
//Save Image
Yush::init($l);
// Nothing has been uploaded yet but YUSH will return a full path that can be used to save the resource
$originalPath = Yush::getPath($l, Yush::SIZE_ORIGINAL, $l->path);
// Save the original resource to disk
$image->saveAs($originalPath);
$thumbPath = Yush::getPath($l, Yush::SIZE_THUMB, $l->path);
// Create a thumbnail
// Kohana Image library
$thumbImage = Yii::app()->image->load($originalPath);
$thumbImage->resize(350, 350)->rotate(0)->quality(100)->sharpen(10);
// $thumbImage = PhpThumbFactory::create($originalPath);
// $thumbImage->resize(350, 350);
switch ($thumbImage->save($thumbPath)) {
case true:
Yii::app()->user->setFlash('success', self::MESSAGE_SUCCESS);
$this->redirect(Yii::app()->params->local . 'merchant/profile');
break;
default:
# code...
Yii::app()->user->setFlash('error', self::MESSAGE_FAILURE);
$this->redirect(Yii::app()->params->local . 'merchant/profile');
break;
}
}
else
{
Yii::app()->user->setFlash('error', self::MESSAGE_FAILURE);
$this->redirect(Yii::app()->params->local . 'merchant/profile');
}
break;
}
Does anybody have any idea what the problem might be??

Jquery causes unintended DB row creation in cake

I have this jquery code in a view, relating to my uploads controller:
function screenshot(){
var dataUrl = renderer.domElement.toDataURL("image/png");
$.post("picturepicker", {dataUrl: dataUrl, uploadnumber: 2
}
}
It successfully sends data to this function:
public function picturepicker(){
...
if($this->request->is('post')){
define('UPLOAD_DIR', WWW_ROOT . 'img/'); // increase validation
$img = $_POST['dataUrl']; // Tried $this->request['dataURL'], retrieved 'dataURL' just fine
$upload = $_POST['uploadnumber']; // tried $this->request['uploadnumber'], did not retrieve 'uploadnumber'
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . $upload . '.png'; // UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
Which works fine, except that every time I ran the javascript, a new database row is created. Since I have no create function, I imagine that somehow jquery is inadvertently calling this function:
public function upload(){
if ($this->request->is('post')) {
//var_dump($this->request->data);
$this->Upload->create();
....
However, I doubt that since the rows are still added even when I delete all references to the create function.
So why might this happen, and how should I fix it? I am suspecting that somehow the jquery code is calling all of my functions, and that I need to put an if block around any of the others that take post data. I have been told that this should not be the case, and that perhaps cake's routing is to blame. Alternatively, I might have missed something in the cake documentation - perhaps cake is set up to make a new DB row for EVERY post request, and I need to tell it not to somehow.

html2canvas custom proxy in php

This is my first question on here so be nice....
I am trying to use html2canvas to ultimately get a screenshot of a remote site (user submitted url).
The problem is the cross domain security features. I cannot read from the canvas as it's locked by off site assets.
The solution is to use the proxy feature built into the library.
There are some github projects with python and node.js versions, but I'm needing to do it in php.
There are many topics on HOW to implement the feature and how to get it working, but none really explain how to make your own proxy.
My question is two fold, are there any existing solutions in PHP? and if not, I have a few questions on making my own:
1.) What is the output format of the proxy? json object? the rendered image? the base64 encoded data string?
2.) Do these files need to persist on the server or can they just be rendered then disappear (overwritten)?
This is roughly what i'm thinking:
$img_url = urldecode($_GET['url']);
$img_data = base64_encode(file_get_contents($img_url));
//shouldn't need it since it's not cross domain now, but a CORS header could be inserted
header('content-type: application/json; charset=utf-8');
json_encode("{$_GET['callback']}($img_data)");
I've found the answers to my question.
The proxy feature accepts a jsonp element with the url to the proxied image.
And they do need to be saved on the server while
This is raw, I will update it later, but here is a working PHP proxy script for html2canvas
session_start();
//parse the url sent by the proxy function
//TODO: scrub the input
$img_url = urldecode($_GET['url']);
//test file type
//TODO: test for other cases that don't have a '.'
$pos = strrpos($img_url, '.', -1);
$ext = substr($img_url, $pos);
//set a dir for this request
function randomNumber()
{
return substr(sha1(rand()), 0, 15);
}
if (!isset($_COOKIE["img_path"]))
{
do{
$random = randomNumber();
}while (is_dir('images/' . $random));
setcookie("img_path", $random, time()+3600);
} else {
$random = $_COOKIE["img_path"];
}
is_dir('images/' . $random) ? '' : mkdir('images/' . $random, 0755);
//TODO:catch cases where a filename isn't the last element
$basename = basename($img_url);
$file = 'images/' . $random . '/' . $basename;
//save the image
copy($img_url, $file);
//TODO: don't hardcode the url
$test_location = "http://osc.test/html2canvas2/" . $file;
header('Content-Type: application/javascript');
echo "{$_GET['callback']}(" . json_encode($test_location) . ")";
In case anyone else is looking for a simple PHP proxy, here is a link to a nice one by "Cowboy" Ben Alman:
Simple PHP proxy

Categories