File "FirefoxProfile.php"
Full Path: /home/clickysoft/public_html/jmapi5.clickysoft.net/vendor/php-webdriver/webdriver/lib/Firefox/FirefoxProfile.php
File size: 9.15 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Facebook\WebDriver\Firefox;
use Facebook\WebDriver\Exception\Internal\IOException;
use Facebook\WebDriver\Exception\Internal\LogicException;
use Facebook\WebDriver\Exception\Internal\RuntimeException;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ZipArchive;
class FirefoxProfile
{
/**
* @var array
*/
private $preferences = [];
/**
* @var array
*/
private $extensions = [];
/**
* @var array
*/
private $extensions_datas = [];
/**
* @var string
*/
private $rdf_file;
/**
* @param string $extension The path to the xpi extension.
* @return FirefoxProfile
*/
public function addExtension($extension)
{
$this->extensions[] = $extension;
return $this;
}
/**
* @param string $extension_datas The path to the folder containing the datas to add to the extension
* @return FirefoxProfile
*/
public function addExtensionDatas($extension_datas)
{
if (!is_dir($extension_datas)) {
return null;
}
$this->extensions_datas[basename($extension_datas)] = $extension_datas;
return $this;
}
/**
* @param string $rdf_file The path to the rdf file
* @return FirefoxProfile
*/
public function setRdfFile($rdf_file)
{
if (!is_file($rdf_file)) {
return null;
}
$this->rdf_file = $rdf_file;
return $this;
}
/**
* @param string $key
* @param string|bool|int $value
* @throws LogicException
* @return FirefoxProfile
*/
public function setPreference($key, $value)
{
if (is_string($value)) {
$value = sprintf('"%s"', $value);
} else {
if (is_int($value)) {
$value = sprintf('%d', $value);
} else {
if (is_bool($value)) {
$value = $value ? 'true' : 'false';
} else {
throw LogicException::forError(
'The value of the preference should be either a string, int or bool.'
);
}
}
}
$this->preferences[$key] = $value;
return $this;
}
/**
* @param mixed $key
* @return mixed
*/
public function getPreference($key)
{
if (array_key_exists($key, $this->preferences)) {
return $this->preferences[$key];
}
return null;
}
/**
* @return string
*/
public function encode()
{
$temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile');
if (isset($this->rdf_file)) {
copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . 'mimeTypes.rdf');
}
foreach ($this->extensions as $extension) {
$this->installExtension($extension, $temp_dir);
}
foreach ($this->extensions_datas as $dirname => $extension_datas) {
mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname);
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $item) {
$target_dir = $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR
. $iterator->getSubPathName();
if ($item->isDir()) {
mkdir($target_dir);
} else {
copy($item, $target_dir);
}
}
}
$content = '';
foreach ($this->preferences as $key => $value) {
$content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value);
}
file_put_contents($temp_dir . '/user.js', $content);
// Intentionally do not use `tempnam()`, as it creates empty file which zip extension may not handle.
$temp_zip = sys_get_temp_dir() . '/' . uniqid('WebDriverFirefoxProfileZip', false);
$zip = new ZipArchive();
$zip->open($temp_zip, ZipArchive::CREATE);
$dir = new RecursiveDirectoryIterator($temp_dir);
$files = new RecursiveIteratorIterator($dir);
$dir_prefix = preg_replace(
'#\\\\#',
'\\\\\\\\',
$temp_dir . DIRECTORY_SEPARATOR
);
foreach ($files as $name => $object) {
if (is_dir($name)) {
continue;
}
$path = preg_replace("#^{$dir_prefix}#", '', $name);
$zip->addFile($name, $path);
}
$zip->close();
$profile = base64_encode(file_get_contents($temp_zip));
// clean up
$this->deleteDirectory($temp_dir);
unlink($temp_zip);
return $profile;
}
/**
* @param string $extension The path to the extension.
* @param string $profileDir The path to the profile directory.
* @throws IOException
*/
private function installExtension($extension, $profileDir)
{
$extensionCommonName = $this->parseExtensionName($extension);
// install extension to profile directory
$extensionDir = $profileDir . '/extensions/';
if (!is_dir($extensionDir) && !mkdir($extensionDir, 0777, true) && !is_dir($extensionDir)) {
throw IOException::forFileError(
'Cannot install Firefox extension - cannot create directory',
$extensionDir
);
}
if (!copy($extension, $extensionDir . $extensionCommonName . '.xpi')) {
throw IOException::forFileError(
'Cannot install Firefox extension - cannot copy file',
$extension
);
}
}
/**
* @param string $prefix Prefix of the temp directory.
*
* @throws IOException
* @return string The path to the temp directory created.
*/
private function createTempDirectory($prefix = '')
{
$temp_dir = tempnam(sys_get_temp_dir(), $prefix);
if (file_exists($temp_dir)) {
unlink($temp_dir);
mkdir($temp_dir);
if (!is_dir($temp_dir)) {
throw IOException::forFileError(
'Cannot install Firefox extension - cannot create directory',
$temp_dir
);
}
}
return $temp_dir;
}
/**
* @param string $directory The path to the directory.
*/
private function deleteDirectory($directory)
{
$dir = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS);
$paths = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($paths as $path) {
if ($path->isDir() && !$path->isLink()) {
rmdir($path->getPathname());
} else {
unlink($path->getPathname());
}
}
rmdir($directory);
}
/**
* @param string $xpi The path to the .xpi extension.
* @param string $target_dir The path to the unzip directory.
*
* @throws IOException
* @return FirefoxProfile
*/
private function extractTo($xpi, $target_dir)
{
$zip = new ZipArchive();
if (file_exists($xpi)) {
if ($zip->open($xpi)) {
$zip->extractTo($target_dir);
$zip->close();
} else {
throw IOException::forFileError('Failed to open the firefox extension.', $xpi);
}
} else {
throw IOException::forFileError('Firefox extension doesn\'t exist.', $xpi);
}
return $this;
}
private function parseExtensionName($extensionPath)
{
$temp_dir = $this->createTempDirectory();
$this->extractTo($extensionPath, $temp_dir);
$mozillaRsaPath = $temp_dir . '/META-INF/mozilla.rsa';
$mozillaRsaBinaryData = file_get_contents($mozillaRsaPath);
$mozillaRsaHex = bin2hex($mozillaRsaBinaryData);
//We need to find the plugin id. This is the second occurrence of object identifier "2.5.4.3 commonName".
//That is marker "2.5.4.3 commonName" in hex:
$objectIdentifierHexMarker = '0603550403';
$firstMarkerPosInHex = strpos($mozillaRsaHex, $objectIdentifierHexMarker); // phpcs:ignore
$secondMarkerPosInHexString =
strpos($mozillaRsaHex, $objectIdentifierHexMarker, $firstMarkerPosInHex + 2); // phpcs:ignore
if ($secondMarkerPosInHexString === false) {
throw RuntimeException::forError('Cannot install extension. Cannot fetch extension commonName');
}
// phpcs:ignore
$commonNameStringPositionInBinary = ($secondMarkerPosInHexString + strlen($objectIdentifierHexMarker)) / 2;
$commonNameStringLength = ord($mozillaRsaBinaryData[$commonNameStringPositionInBinary + 1]);
// phpcs:ignore
$extensionCommonName = substr(
$mozillaRsaBinaryData,
$commonNameStringPositionInBinary + 2,
$commonNameStringLength
);
$this->deleteDirectory($temp_dir);
return $extensionCommonName;
}
}