使用PHP的Selenium WebDriver远程上传文件

8
我一直在StackOverflow(和其他资源)上搜索如何使用PHP远程上传文件到Selenium WebDriver。我阅读了这个http://saucelabs.com/blog/index.php/2012/03/selenium-tips-uploading-files-in-remote-webdriver/,它提到需要通过“setFileDetector”方法改变你正在使用的WebDriver库的工作方式。
如果我使用Ruby或Java,这应该是有效的。但是大多数PHP框架没有这种方法。
有人可以告诉我如何在PHP中实现这一点吗?具体来说,我正在使用phpwebdriver库http://code.google.com/p/php-webdriver-bindings/
1个回答

10

通过查看SauceLabs.com博客文章(https://saucelabs.com/jobs/1a408cf60af0601f49052f66fa37812c/selenium-server.log)上的原始日志,我能够确定上传文件的JsonWireProtocol应该是/session/<sessionId>/file,因此,我创建了这个函数添加到php-webdriver-bindings库中:

/**
 * 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;
}

将此内容添加到 WebDriver.php 文件中。

使用时,只需像这样操作:

...
$file_location = $webdriver->sendFile('http://test.com/some/file.zip');
$file_input = $webdriver->findElementBy(LocatorStrategy::id, 'uploadfile');
$file_input->sendKeys(array($file_location));

希望这能帮助其他开发者,我花了将近3个小时寻找答案。

更新:

由于出现了错误,我不得不进行更改:

Expected there to be only 1 file. There were: 0

希望将这里放置可以得到谷歌搜索结果(我尝试在谷歌上搜索错误信息,但唯一能找到的结果是关于谷歌代码源的参考资料)。

为了解决这个问题,我能够推断出你发送的文件实际上需要被压缩。因此,我增强了源代码,使用了PHP的ZipArchive库。 我会保留旧代码用于记录,但请使用这里的新代码:

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);
}

更新:事实证明,您需要在$zip->addFile()方法上设置两个参数。已编辑上面的代码以反映这些更改。


非常感谢您提供这个信息。在 JSON Wire Protocol 页面上没有找到它(至少 Command+F 没有搜索到)。谢谢。 - K-RAN
@K-RAN,该功能并非JSONWireProtocol的正式部分。解决方案是从官方语言绑定的反向工程中推导出来的。这太糟糕了,不是吗? - David
@David 刚刚查看了 Github 的问题页面,但是没有找到你所说的确切内容(也许我读错了哈哈)。不过我已经向你发送了一个拉取请求。 - K-RAN
@K-RAN,关于项目页面上的问题,我是指原始项目还是Google Code上的项目。你可能在考虑不同的PHP绑定,或者是Google Code的一个分支(我在GitHub上复制了一份)。http://code.google.com/p/php-webdriver-bindings/issues/detail?id=35 - David
这个问题现在应该已经被修复/整合到Google代码项目的PHP绑定中了。 - David
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接