Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading files remotely on Selenium WebDriver using 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/

like image 718
Nikko Avatar asked May 11 '12 23:05

Nikko


1 Answers

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.

like image 176
Nikko Avatar answered Oct 06 '22 05:10

Nikko