Uploading files remotely on Selenium WebDriver using PHP - php

I've been searching around StackOverflow (and other resources) on how to remotely upload files on Selenium WebDriver with PHP. I've read this http://saucelabs.com/blog/index.php/2012/03/selenium-tips-uploading-files-in-remote-webdriver/, and it mentions that you need to use a "setFileDetector" method somehow to change the way the WebDriver library you're using works.
This should work fine if I was using Ruby or Java. Most PHP frameworks on the other hand don't have this method.
Can anybody tell me how to do this in PHP? Specifically, I'm using the phpwebdriver library http://code.google.com/p/php-webdriver-bindings/

I was able to determine that the JsonWireProtocol to upload a file would be /session/<sessionId>/file by checking out the raw log on the SauceLabs.com blog post (https://saucelabs.com/jobs/1a408cf60af0601f49052f66fa37812c/selenium-server.log) so with that, I created this function to add-in to the php-webdriver-bindings library:
/**
* Send a file to your Remote WebDriver server
* This will return the local URL of the file you uploaded, which will then
* let you use sendKeys in file input elements
* #params String $value - a local or remote file to send
* #return String $resopnseValue - the local directory where the file resides on the remote server
*/
public function sendFile($value) {
$file = #file_get_contents($value);
if( $file === false ) {
return false;
}
$file = base64_encode($file);
$request = $this->requestURL . "/file";
$session = $this->curlInit($request);
$args = array( 'file' => $file );
$postargs = json_encode($args);
$this->preparePOST($session, $postargs);
$response = trim(curl_exec($session));
$responseValue = $this->extractValueFromJsonResponse($response);
return $responseValue;
}
Add this to the WebDriver.php file.
To use, just do something like this:
...
$file_location = $webdriver->sendFile('http://test.com/some/file.zip');
$file_input = $webdriver->findElementBy(LocatorStrategy::id, 'uploadfile');
$file_input->sendKeys(array($file_location));
I hope this will help other developers, spent like 3 hours looking for the answer to this.
Update:
I had to change this due to getting this error:
Expected there to be only 1 file. There were: 0
Hopefully putting this here would get Google results (I tried searching for the error message on Google and the only results it could find were the references to the source code on Google Code).
To solve this problem, I was able to deduce that the file you send actually needs to be zipped. So I've augmented the source code to use PHP's ZipArchive library. I will keep the old code on top for record-keeping, but please use the new code here:
public function sendFile($value, $file_extension = '')
{
$zip = new ZipArchive();
$filename_hash = sha1(time().$value);
$zip_filename = "{$filename_hash}_zip.zip";
if( $zip->open($zip_filename, ZIPARCHIVE::CREATE) === false ) {
echo 'WebDriver sendFile $zip->open failed\n';
return false;
}
$file_data = #file_get_contents($value);
if( $file_data === false ) {
throw new Exception('WebDriver sendFile file_get_contents failed');
}
$filename = "{$filename_hash}.{$file_extension}";
if( #file_put_contents($filename, $file_data) === false ) {
throw new Exception('WebDriver sendFile file_put_contents failed');
}
$zip->addFile($filename, "{$filename_hash}.{$file_extension}");
$zip->close();
$zip_file = #file_get_contents($zip_filename);
if( $zip_file === false ) {
throw new Exception('WebDriver sendFile file_get_contents for $zip_file failed');
}
$file = base64_encode($zip_file);
$request = $this->requestURL . "/file";
$session = $this->curlInit($request);
$args = array( 'file' => $file );
$postargs = json_encode($args);
$this->preparePOST($session, $postargs);
$response = trim(curl_exec($session));
return $this->extractValueFromJsonResponse($response);
}
Update: Turns out, you need to set two parameters on the $zip->addFile() method. Edited the above code to reflect the changes.

Related

open file on client stored on server

I want to open a server stored html report file on a client machine.
I want to bring back a list of all the saved reports in that folder (scandir).
This way the user can click on any of the crated reports to open them.
So id you click on a report to open it, you will need the location where the report can be opend from
This is my dilemma. Im not sure how to get a decent ip, port and folder location that the client can understand
Here bellow is what Ive been experimenting with.
Using this wont work obviously:
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
So I though I might try this instead.
$host= gethostname();
$ip = gethostbyname($host);
$ip = $ip.':'.$_SERVER['SERVER_PORT'];
$path = $ip."/reports/saved_reports/";
$files = scandir($path);
after the above code I loop through each file and generate a array with the name, date created and path. This is sent back to generate a list of reports in a table that the user can interact with. ( open, delete, edit)
But this fails aswell.
So im officially clueless on how to approach this.
PS. Im adding react.js as a tag, because that is my front-end and might be useful to know.
Your question may be partially answered here: https://stackoverflow.com/a/11970479/2781096
Get the file names from the specified path and hit curl or get_text() function again to save the files.
function get_text($filename) {
$fp_load = fopen("$filename", "rb");
if ( $fp_load ) {
while ( !feof($fp_load) ) {
$content .= fgets($fp_load, 8192);
}
fclose($fp_load);
return $content;
}
}
$matches = array();
// This will give you names of all the files available on the specified path.
preg_match_all("/(a href\=\")([^\?\"]*)(\")/i", get_text($ip."/reports/saved_reports/"), $matches);
foreach($matches[2] as $match) {
echo $match . '<br>';
// Again hit a cURL to download each of the reports.
}
Get list of reports:
<?php
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
$files = scandir($path);
foreach($files as $file){
if($file !== '.' && $file != '..'){
echo "<a href='show-report.php?name=".$file. "'>$file</a><br/>";
}
}
?>
and write second php file for showing html reports, which receives file name as GET param and echoes content of given html report.
show-report.php
<?php
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
if(isset($_GET['name'])){
$name = $_GET['name'];
echo file_get_contents($path.$name);
}

wordpress recursive zip folder file download php / path issue

I know there is quite some code out there about that topic. But I can't get the code I found to work...
I'm using a function that comes from a Wordpress plugin called Zip-Attachments.
So I modified it to zip files from a specific folder. BUT it doesn't work....
It seems as if I'm missing something when it comes to accurately assigning a paths within the RecursiveDirectoryIterator class.
I was able to zip a single file and downloading it without the recursiveIteration functionality and passing the absolute path as a string. So the main part of the function works.
What am I missing to make that function work?
Here is my non working code:
function za_create_zip_callback(){
$upload_dir = wp_upload_dir();
$rootPath = $upload_dir['basedir'];
$upload_dir_Knippsbox = 'Knippsbox';
// Prepare File
$file = tempnam($upload_dir['path'], "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);
// create recursive directory iterator
$files = new RecursiveIteratorIterator (new RecursiveDirectoryIterator("{$rootPath}/{$upload_dir_Knippsbox}/"), RecursiveIteratorIterator::LEAVES_ONLY);
// let's iterate
foreach ($files as $name => $fileX) {
$filePath = $fileX->getRealPath();
$zip->addFile($filePath);
}
//Close the file
$zip->close();
// Add a download to the Counter
global $wpdb;
$meta_name = "_za_counter";
// Retrieve the meta value from the DB
$za_download_count = get_post_meta($postId, $meta_name, true) != '' ? get_post_meta($postId, $meta_name, true) : '0';
$za_download_count = $za_download_count + 1;
// Update the meta value
update_post_meta($postId, $meta_name, $za_download_count);
// We have to return an actual URL, that URL will set the headers to force the download
echo zip_attachments_url."/download.php?za_pretty_filename=".sanitize_file_name($pretty_filename)."&za_real_filename=".$filename;
die();}
Desperately looking for your expert views...
Thanks,
Ben

Check if file exists in .tar using PHP

In my program I need to read .png files from a .tar file.
I am using pear Archive_Tar class (http://pear.php.net/package/Archive_Tar/redirected)
Everything is fine if the file im looking for exists, but if it is not in the .tar file then the function timouts after 30 seconds. In the class documentation it states that it should return null if it does not find the file...
$tar = new Archive_Tar('path/to/mytar.tar');
$filePath = 'path/to/my/image/image.png';
$file = $tar->extractInString($filePath); // This works fine if the $filePath is correct
// if the path to the file does not exists
// the script will timeout after 30 seconds
var_dump($file);
return;
Any suggestions on solving this or any other library that I could use to solve my problem?
The listContent method will return an array of all files (and other information about them) present in the specified archive. So if you check if the file you wish to extract is present in that array first, you can avoid the delay that you are experiencing.
The below code isn't optimised - for multiple calls to extract different files for example the $files array should only be populated once - but is a good way forward.
include "Archive/Tar.php";
$tar = new Archive_Tar('mytar.tar');
$filePath = 'path/to/my/image/image.png';
$contents = $tar->listContent();
$files = array();
foreach ($contents as $entry) {
$files[] = $entry['filename'];
}
$exists = in_array($filePath, $files);
if ($exists) {
$fileContent = $tar->extractInString($filePath);
var_dump($fileContent);
} else {
echo "File $filePath does not exist in archive.\n";
}

Create a ZIP file script not creating ZIPs (no errors)

I'm not a native PHP developer but I make do with what I can find and hack together out there, so please excuse me if this doesn't make too much sense:
I have a simple (so it seems) script that takes two arguments in the URL. One is a simple string (title of the ZIP to be created) and the other is a serialized array of audio tracks that point to the files on the server that need zipping. These then pass just fine and are unserialized etc. Here's the script:
<?php
$audioTitleVar = unserialize(rawurldecode($_GET['audioTitle']));
$audioArrayVar = unserialize(rawurldecode($_GET['audioArray']));
function create_zip( $files = array(), $destination = '', $overwrite = true ) {
if(file_exists($destination) && !$overwrite) { return false; }
$valid_files = array();
if(is_array($files)) {
foreach($files as $file) {
if( file_exists($_SERVER['DOCUMENT_ROOT'] . str_replace("http://mydomain.com","", $file)) ) {
$valid_files[] = $_SERVER['DOCUMENT_ROOT'] . str_replace("http://mydomain.com","", $file);
}
}
}
if(count($valid_files)) {
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
foreach( $valid_files as $file ) {
$just_name = preg_replace("/(.*)\/?([^\/]+)/","$2",$file);
$zip->addFile($file,$just_name);
//$zip->addFile($file,$file);
}
//echo '<p>The zip archive contains ' . $zip->numFiles . ' files with a status of ' . $zip->status . '</p>';
$zip->close();
return file_exists($destination);
} else {
return false;
}
}
$fileName = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/themes/jones/zip/' . $audioTitleVar . '.zip';
create_zip( $audioArrayVar, $fileName, true );
//echo '<p>File Path: ' . $fileName . '</p>';
var_dump(file_exists($fileName));
?>
I guess my real issue here, is that, although the script DOES NOT error...no ZIP is created. I have, over time placed outputs in the function at certain parts to see if it was even getting there, and it is - so I'm stumped on this.
What I really need is for one of you guys to scan the script over to see if there's anything glaringly obvious that just won't work!
Could it be a permissions thing? Should PHP be running in CGI mode or Apache? Or does this not make a difference?
The bones of this script were taken from: http://davidwalsh.name/create-zip-php but it's never worked even with that version alone.
PS - I'd just like to add, that if I uncomment the line that tells me how many files are in the ZIP etc, it seems to return the correct info...but the final check on whether the file exists returns false.
Ok, I have finally got it working.
Seems there was something in the addFile() that corrupted the code.
I changed this:
foreach( $valid_files as $file ) {
$just_name = preg_replace("/(.*)\/?([^\/]+)/","$2",$file);
$zip->addFile($file,$just_name);
//$zip->addFile($file,$file);
}
To this:
foreach( $valid_files as $file ) {
// Use basename to get JUST the file name from the path.
$zip->addFile($file, basename($file) );
}
The basename function gets only the file NAME to then place in the ZIP. Before it was the whole path on the server, and this was causing Windows to choke on it.
Hope this helps someone someday.

Remote Zip Extraction > Can't seem to get this to the finish line

The purpose of this code is to grab an update.zip file from a remote server, unzip it and save it to a local directory, updating, overwriting or creating the updated files.
I've almost got a non cURL version of this working, but I'd rather use this version. The first problem I have is that the path to the tmp folder is incorrect. I need a better method of sniffing that out (temporarily hardcoded)...
The 2nd problem is that the code's not working, but its not throwing an error. Its executing the $x branch but no zip extraction is taking place.
require('../../../wp-blog-header.php'); //enables wp security check and ABSPATH
$payload = file_get_contents('http://myserver.com/upgrade.zip'); //grab the file from the remote server
$target = ABSPATH .'wp-content/themes/mytheme/'; // this is the destination for the unzipped files
openZip($payload);
function openZip($file_to_open, $debug = false) {
global $target;
$file = ABSPATH . '/tmp/'.md5($file_to_open).'.zip'; //this should be home/myfolder/tmp but ABSPATH is giving the wrong path to the tmp directory.
$client = curl_init($file_to_open);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$fileData = curl_exec($client);
file_put_contents($file, $fileData);
$zip = new ZipArchive();
$x = $zip->open($file);
if($x === true) { //this is true, but no zip extraction?
$zip->extractTo($target);
$zip->close();
unlink($file);
} else {
if($debug !== true) {
unlink($file);
}
die("There was a problem. Please try again!");
}
}
The most likely cause here is that you're not actually writing the zip file data in your file_put_contents() call inside openZip. If you pass a zero-length file to $zip->open(), it will happily go about its way returning (bool)true, even though you obviously will not be able to extract anything from it. See this example.

Categories