Final
This commit is contained in:
parent
b641f863e8
commit
30f33f1f0c
|
@ -1,2 +1,3 @@
|
|||
/vendor/
|
||||
*~
|
||||
*~
|
||||
.idea/
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ComposerJsonPluginSettings">
|
||||
<unboundedVersionInspectionSettings>
|
||||
<excludedPackages />
|
||||
</unboundedVersionInspectionSettings>
|
||||
<customRepositories />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PublishConfigData" serverName="Symfony" />
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
$header = <<<'EOF'
|
||||
This file is part of Selenium Tor Driver.
|
||||
(c) R. Eric Wheeler <eric@rewiv.com>
|
||||
This source file is subject to the MIT license that is bundled
|
||||
with this source code in the file LICENSE.
|
||||
EOF;
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in([__DIR__ . '/src', __DIR__ . '/Tests']);
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'header_comment' => [
|
||||
'header' => $header
|
||||
],
|
||||
])
|
||||
->setFinder($finder);
|
|
@ -0,0 +1,55 @@
|
|||
## Selenium Tor Implementation for [facebook/php-webdriver](https://github.com/facebook/php-webdriver)
|
||||
|
||||
### Usage
|
||||
|
||||
#### Install Composer
|
||||
|
||||
* `curl -SsL https://getcomposer.org/installer|php`
|
||||
* `mv composer.phar /usr/local/bin/composer`
|
||||
|
||||
#### Get the code
|
||||
|
||||
* Clone the repository `git clone https://repos.bgemi.net/sikofitt/selenium-tor`
|
||||
* `cd selenium-tor`
|
||||
|
||||
#### Install dependencies
|
||||
* Then install the dependencies with `composer install`
|
||||
|
||||
#### Get tor if you don't have it
|
||||
* `composer download` or
|
||||
* `bin/console tor:download`
|
||||
|
||||
```php
|
||||
use Sikofitt\WebDriver\FirefoxBinary;
|
||||
use Sikofitt\WebDriver\Remote\DesiredCapabilities;
|
||||
use Sikofitt\WebDriver\Tor\TorProfile;
|
||||
use Sikofitt\WebDriver\TorLauncher;
|
||||
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$firefoxBinary = new FirefoxBinary(__DIR__ . '/../tor-browser_en-US/Browser/start-tor-browser');
|
||||
$caps = DesiredCapabilities::tor($firefoxBinary);
|
||||
$profile = new TorProfile();
|
||||
$caps->setCapability('timeout', 3600);
|
||||
$caps->setCapability(FirefoxDriver::PROFILE, $profile);
|
||||
|
||||
$torProcess = TorLauncher::launch($firefoxBinary);
|
||||
// Wait for Tor to connect
|
||||
sleep(2);
|
||||
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $caps);
|
||||
$this->webDriver->navigate()->to('http://32b5oz2bbtn6gqj3.onion');
|
||||
// Or $this-webDriver->get('http://32b5oz2bbtn6gqj3.onion');
|
||||
$pageImages = $this->webDriver->findElements(WebDriverBy::tagName('img'));
|
||||
$images = [];
|
||||
foreach($pageImages as $image)
|
||||
{
|
||||
$images[] = $image->getAttribute('src');
|
||||
}
|
||||
TorLauncher::stop($torProcess);
|
||||
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
`composer test'`
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Sikofitt\WebDriver\FirefoxBinary;
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: eric
|
||||
* Date: 12/20/16
|
||||
* Time: 1:33 PM
|
||||
*/
|
||||
class FireFoxBinaryTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testBinaryFail()
|
||||
{
|
||||
$fireFoxBinary = new FirefoxBinary('file');
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
class GitHubTests extends PHPUnit_Framework_TestCase {
|
||||
|
||||
protected $webDriver;
|
||||
protected $url = 'https://github.com';
|
||||
|
||||
public function setUp() {
|
||||
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', DesiredCapabilities::firefox());
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->webDriver->quit();
|
||||
}
|
||||
public function testGitHubHome() {
|
||||
$this->webDriver->get($this->url);
|
||||
$this->assertContains('GitHub', $this->webDriver->getTitle());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Sikofitt\WebDriver\FirefoxBinary;
|
||||
use Sikofitt\WebDriver\Remote\DesiredCapabilities;
|
||||
use Sikofitt\WebDriver\Tor\TorProfile;
|
||||
use Sikofitt\WebDriver\TorLauncher;
|
||||
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Class SeleniumTorTests
|
||||
*/
|
||||
class SeleniumTorSimpleTests extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $webDriver;
|
||||
protected $urls = [
|
||||
'http://skunksworkedp2cg.onion/sites.html' => 'A list of onion sites ordered by hostname',
|
||||
'http://32b5oz2bbtn6gqj3.onion' => 'The Hidden Wiki',
|
||||
];
|
||||
|
||||
protected $process;
|
||||
protected $torProcess;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$firefoxBinary = new FirefoxBinary(__DIR__ . '/../tor-browser_en-US/Browser/start-tor-browser');
|
||||
$caps = DesiredCapabilities::tor($firefoxBinary);
|
||||
$profile = new TorProfile();
|
||||
$caps->setCapability('timeout', 3600);
|
||||
$caps->setCapability(FirefoxDriver::PROFILE, $profile);
|
||||
|
||||
$this->torProcess = TorLauncher::launch($firefoxBinary);
|
||||
|
||||
// Wait for Tor to connect
|
||||
sleep(2);
|
||||
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $caps);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->webDriver->quit();
|
||||
TorLauncher::stop($this->torProcess);
|
||||
}
|
||||
|
||||
|
||||
public function testOnionCoreSite()
|
||||
{
|
||||
foreach ($this->urls as $url => $title) {
|
||||
$this->webDriver->navigate()->to($url);
|
||||
$elements = $this->webDriver->findElements(WebDriverBy::tagName('img'));
|
||||
$this->assertEquals($title, $this->webDriver->getTitle());
|
||||
$images = [];
|
||||
foreach ($elements as $element) {
|
||||
$images[] = $element->getAttribute('src');
|
||||
}
|
||||
file_put_contents(__DIR__ . '/../' . 'data.json', json_encode($images, JSON_PRETTY_PRINT));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: eric
|
||||
* Date: 12/20/16
|
||||
* Time: 8:26 AM
|
||||
*/
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
define('BASE_DIR', __DIR__ . '/../');
|
||||
$app = new Application('Selenium tests', '0.0.1');
|
||||
|
||||
$app->add(new Sikofitt\Console\Command\TorBrowserDownloadCommand());
|
||||
|
||||
$app->run();
|
|
@ -1,9 +1,22 @@
|
|||
{
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"facebook/webdriver": "^1.2",
|
||||
"se/selenium-server-standalone": "~2"
|
||||
"friendsofphp/php-cs-fixer": "^2.0"
|
||||
},
|
||||
"require": {
|
||||
"facebook/webdriver": "dev-master",
|
||||
"se/selenium-server-standalone": "~2",
|
||||
"guzzlehttp/guzzle": "^6.2",
|
||||
"symfony/console": "^3.2",
|
||||
"symfony/process": "^3.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sikofitt\\":"src/Sikofitt"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"tests": "vendor/bin/phpunit",
|
||||
"download":"php bin/console tor:download"
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
|||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
|
||||
backupGlobals="true"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
cacheTokens="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
forceCoversAnnotation="false"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
stopOnIncomplete="false"
|
||||
stopOnSkipped="false"
|
||||
stopOnRisky="false"
|
||||
timeoutForSmallTests="3600"
|
||||
timeoutForMediumTests="3600"
|
||||
timeoutForLargeTests="3600"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="Selenium Tests">
|
||||
<directory suffix=".php">Tests/</directory>
|
||||
<exclude>src/</exclude>
|
||||
<file>*.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\Console\Command;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Class TorBrowserDownloadCommand
|
||||
*
|
||||
* @package Sikofitt\Console\Command
|
||||
*/
|
||||
class TorBrowserDownloadCommand extends Command
|
||||
{
|
||||
const TOR_VERSION = '6.0.8';
|
||||
const TOR_DOWNLOAD_URL = 'https://www.torproject.org/dist/torbrowser';
|
||||
const TOR_PACKAGE_LINUX_I386 = 'tor-browser-linux32-6.0.8_en-US.tar.xz';
|
||||
const TOR_PACKAGE_LINUX_X64 = 'tor-browser-linux64-6.0.8_en-US.tar.xz';
|
||||
const TOR_PACKAGE_WIN = 'torbrowser-install-6.0.8_en-US.exe';
|
||||
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('tor:download')
|
||||
->setDescription('Downloads the tor browser.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads and extracts the tor browser.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return void
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->url = $this->getDownloadUrl();
|
||||
$io = $this->getStyle($input, $output);
|
||||
|
||||
$download = $io->confirm('Download Tor?', true);
|
||||
if (false === $download) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
$io->note('Downloading ' . $this->getDownloadUrl() . ' ...');
|
||||
if (false === file_exists(BASE_DIR . $this->getFileName())) {
|
||||
$client = new Client();
|
||||
try {
|
||||
$data = $client->get($this->url);
|
||||
} catch (\Exception $e) {
|
||||
$io->error($e->getMessage());
|
||||
exit;
|
||||
}
|
||||
|
||||
file_put_contents(BASE_DIR . $this->getFileName(), $data->getBody()->getContents());
|
||||
}
|
||||
$io->success('Downloaded');
|
||||
$io->note('Extracting ...');
|
||||
$tar = new ProcessBuilder();
|
||||
$tar
|
||||
->setPrefix('tar')
|
||||
->setArguments(array('-xvf', BASE_DIR . $this->getFileName()))
|
||||
->getProcess()->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get symfony style
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* The Input instance
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* The output instance
|
||||
*
|
||||
* @return \Symfony\Component\Console\Style\SymfonyStyle
|
||||
* Instance of SymfonyStyle
|
||||
*/
|
||||
private function getStyle(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
return new SymfonyStyle($input, $output);
|
||||
}
|
||||
|
||||
private function getFileName()
|
||||
{
|
||||
$arch = $this->getArch();
|
||||
$os = $this->getOS();
|
||||
|
||||
switch ($os) {
|
||||
case 'linux':
|
||||
default:
|
||||
switch ($arch) {
|
||||
case 'i386':
|
||||
$package = self::TOR_PACKAGE_LINUX_I386;
|
||||
break;
|
||||
case 'x86_64':
|
||||
default:
|
||||
$package = self::TOR_PACKAGE_LINUX_X64;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'win':
|
||||
case 'windows':
|
||||
$package = self::TOR_PACKAGE_WIN;
|
||||
break;
|
||||
}
|
||||
return $package;
|
||||
}
|
||||
|
||||
private function getDownloadUrl()
|
||||
{
|
||||
$package = $this->getFileName();
|
||||
return sprintf('%s/%s/%s', self::TOR_DOWNLOAD_URL, self::TOR_VERSION, $package);
|
||||
}
|
||||
|
||||
private function getArch()
|
||||
{
|
||||
return strtolower(php_uname('m'));
|
||||
}
|
||||
|
||||
private function getOS()
|
||||
{
|
||||
return strtolower(PHP_OS);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class FirefoxBinary
|
||||
*
|
||||
* @package Sikofitt\WebDriver
|
||||
*/
|
||||
class FirefoxBinary extends \SplFileInfo
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $binaryName;
|
||||
|
||||
public function __construct($binaryName)
|
||||
{
|
||||
parent::__construct($binaryName);
|
||||
$this->binaryName = $binaryName;
|
||||
if (false === $this->isExecutable()) {
|
||||
throw new \Exception(sprintf('%s is not executable.', $this->binaryName));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver\Remote;
|
||||
|
||||
use Sikofitt\WebDriver\FirefoxBinary;
|
||||
use WebDriverCapabilityType;
|
||||
use WebDriverPlatform;
|
||||
use DesiredCapabilities as FaceBookDesiredCapabilities;
|
||||
|
||||
class DesiredCapabilities extends FaceBookDesiredCapabilities
|
||||
{
|
||||
|
||||
/**
|
||||
* @param FirefoxBinary|null $firefoxBinary
|
||||
*
|
||||
* @return static DesiredCapabilities
|
||||
*/
|
||||
public static function tor(FirefoxBinary $firefoxBinary = null)
|
||||
{
|
||||
$caps = new static([
|
||||
WebDriverCapabilityType::BROWSER_NAME => 'firefox',
|
||||
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
|
||||
]);
|
||||
if (null !== $firefoxBinary) {
|
||||
$caps->setCapability('firefox_binary', $firefoxBinary->getPathname());
|
||||
}
|
||||
|
||||
return $caps;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver\Tor;
|
||||
|
||||
use FirefoxDriver;
|
||||
|
||||
class TorDriver extends FirefoxDriver
|
||||
{
|
||||
const PROFILE = '/home/eric/projects/selenium-tor/tor-browser_en-US/Browser/TorBrowser/Data/Browser/profile.default';
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver\Tor;
|
||||
|
||||
/**
|
||||
* Class TorPreferences
|
||||
*
|
||||
* @package Sikofitt\WebDriver\Tor
|
||||
*/
|
||||
class TorPreferences extends FirefoxPreferences
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* Port WebDriver uses to communicate with Firefox instance
|
||||
*/
|
||||
const WEBDRIVER_FIREFOX_PORT = 'webdriver_firefox_port';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* Should the reader view (FF 38+) be enabled? NO.
|
||||
* Disable the "Reader View" help tooltip, which can hide elements in the window.document
|
||||
*/
|
||||
const READER_PARSE_ON_LOAD_ENABLED = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* Browser homepage
|
||||
*/
|
||||
const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage';
|
||||
|
||||
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver\Tor;
|
||||
|
||||
use FirefoxProfile;
|
||||
|
||||
class TorProfile extends FirefoxProfile
|
||||
{
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Selenium Tor Driver.
|
||||
* (c) R. Eric Wheeler <eric@rewiv.com>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\WebDriver;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
class TorLauncher
|
||||
{
|
||||
public static function launch(FirefoxBinary $firefoxBinary, $options = [])
|
||||
{
|
||||
$defaultOptions = array(
|
||||
'--detach',
|
||||
'--browser',
|
||||
'--new-instance',
|
||||
'--allow-remote',
|
||||
);
|
||||
|
||||
$defaultOptions += $options;
|
||||
$processBuilder = new ProcessBuilder();
|
||||
$processBuilder
|
||||
->setPrefix($firefoxBinary->getPathname())
|
||||
->setArguments($defaultOptions);
|
||||
$process = $processBuilder->getProcess();
|
||||
$process->start();
|
||||
return $process;
|
||||
}
|
||||
public static function stop(Process $process)
|
||||
{
|
||||
$process->stop(3, SIGKILL);
|
||||
if ('linux' === strtolower(PHP_OS)) {
|
||||
$processBuilder = new ProcessBuilder();
|
||||
$processBuilder->setPrefix('killall')
|
||||
->setArguments(['firefox'])
|
||||
->getProcess()
|
||||
->run();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue