composer do not make good action - php

I try to install via a web admin a module. The action call a function allowing via composer to install a library.
My problem is composer create everytime an htaccess inside my shop directory with an access denied.
Conclusion, it's impossible the display the website
I do not need this htaccess.
How to resolve this problem that.
/shop/.htaccess ===> do not need this files (create automatically)
/shop/composer.lock
/shop/composer.json
public function __construct()
{
static::$root = CORE::getConfig('dir_root', 'Shop');
static::$composerJson = static::$root . 'composer.json';
//define composer environment
putenv('COMPOSER_HOME=' . self::$root);
putenv('COMPOSER_CACHE_DIR=' . CORE::BASE_DIRECTORY . '/Work/Cache/Composer/');
}
public static function install($library = null)
{
if (self::checkExecute() == true) {
if (is_null($library)) {
$result = false;
} else {
$cmd = 'cd ' . self::$root . ' && composer require ' . $library . ' 2>&1';
exec($cmd, $output, $return); // update dependencies
$result = $output[2];
}
return $result;
}
}
Thank you.

Related

Installing with composer via PHP without using exec()

I developed a function using exec() but my hosting company do not allow for exec() functions to be run. How would I get the same result without using exec()?
I need something with the same approach or a library similar to composer which can allow me to install, update, and remove.
Here is what I have at the moment:
public static function install($library = null)
{
if (self::checkExecute() === true) { // check if exec is authorize
if (is_null($library)) {
$result = false;
} else {
$cmd = 'cd ' . self::$root . ' && composer require ' . $library . ' 2>&1';
exec($cmd, $output, $return); // update dependencies
$result = $output[2];
}
return $result;
}
}
https://www.php.net/manual/en/language.operators.execution.php
You could try to see if all shell execution functions are blocked. I would assume so but I've been in your shoes once upon a time.
print `composer install`;

How to get all pending jobs in laravel queue on redis?

The queue:listen was not run on a server, so some jobs were pushed (using Redis driver) but never run.
How could I count (or get all) these jobs? I did not find any artisan command to get this information.
If someone is still looking for an answer, here is the way I did it:
$connection = null;
$default = 'default';
// For the delayed jobs
var_dump(
\Queue::getRedis()
->connection($connection)
->zrange('queues:'.$default.':delayed', 0, -1)
);
// For the reserved jobs
var_dump(
\Queue::getRedis()
->connection($connection)
->zrange('queues:'.$default.':reserved', 0, -1)
);
$connection is the Redis' connection name which is null by default, and the $default is the name of the queue which is default by default.
Since Laravel 5.3 you can simply use Queue::size() (see PR).
You can also use the Redis Facade directly by doing this:
use Redis;
\Redis::lrange('queues:$queueName', 0, -1);
Tested in Laravel 5.6 but should work for all 5.X.
If you are using redis driver for your queue, you can count all remaining jobs by name:
use Redis;
// List all keys with status (awaiting, reserved, delayed)
Redis::keys('*');
// Count by name
$queueName = 'default';
echo Redis::llen('queues:' . $queueName);
// To count by status:
echo Redis::zcount('queues:' . $queueName . ':delayed', '-inf', '+inf');
echo Redis::zcount('queues:' . $queueName . ':reserved', '-inf', '+inf');
To see the result immediately, you can use php artisan tinker and hit Redis::llen('queues:default');.
You can install Horizon.
Laravel Horizon provides a dashboard for monitoring your queues, and allows you to do more configuration to your queue.
composer require laravel/horizon
php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"
You have to set .env config file and config/horizon.php file.
Tested with Laravel 5.6
I have two queues, a default queue and a low_prio queue in my laravel 5.7 project.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class JobsOnQueue extends Command
{
// su -c "php artisan jobs:on:queue" -s /bin/sh www-data
protected $signature = 'jobs:on:queue';
protected $description = 'Print jobs in redis';
protected $lines = [];
public function handle()
{
$connection = null;
$queuename = 'default';
$default_delayed = \Queue::getRedis()
->connection($connection)
->zrange('queues:' . $queuename . ':delayed', -9999, 9999);
$default_reserved = \Queue::getRedis()
->connection($connection)
->zrange('queues:' . $queuename . ':reserved', -9999, 9999);
$queuename = 'low_prio';
$low_prio_delayed = \Queue::getRedis()
->connection($connection)
->zrange('queues:' . $queuename . ':delayed', -9999, 9999);
$low_prio_reserved = \Queue::getRedis()
->connection($connection)
->zrange('queues:' . $queuename . ':reserved', -9999, 9999);
$this->getQueueData('default delayed', $default_delayed);
$this->getQueueData('default reserved', $default_reserved);
$this->getQueueData('low prio delayed', $low_prio_delayed);
$this->getQueueData('low prio reserved', $low_prio_reserved);
$this->info(join("\n", $this->lines));
}
private function getQueueData($title, $arr)
{
$this->lines[] = "*** $title ***";
if (count($arr) == 0) {
$this->lines[] = "Nothing on queue";
$this->lines[] = "";
return;
}
foreach ($arr as $json) {
$queue = json_decode($json);
$data = $queue->data;
if (isset($data) && isset($data->command)) {
$this->getCommands($data->command);
}
}
$this->lines[] = "";
}
private function getCommands($serialized)
{
$readable = str_replace(
'O:43:"Illuminate\Foundation\Console\QueuedCommand',
'O:33:"App\Support\ReadableQueuedCommand',
$serialized);
$readable = unserialize($readable);
$command = $readable->getData();
$attribs = [];
$options = $command[1];
foreach ($options as $key => $value) {
$attribs[] = $key . '=' . $value;
}
$this->lines[] = $command[0] . ' ' . join(" - ", $attribs);
}
}
The ReadableQueuedCommand looks like this
<?php
namespace App\Support;
use Illuminate\Foundation\Console\QueuedCommand;
class ReadableQueuedCommand extends QueuedCommand
{
public function getData()
{
return $this->data;
}
}
The artisan command then lists all in queue
> php artisan jobs:on:queue
*** default delayed ***
Nothing on queue
*** default reserved ***
Nothing on queue
*** low prio delayed ***
Nothing on queue
*** low prio reserved ***
oppty:time:profile --by-dataset=2
oppty:on:reset:pages --by-dataset=2
If anybody is still looking approach for the older versions of the Laravel:
$connection = 'queue';
$queueName = 'default';
$totalQueuedLeads = Redis::connection($connection)
->zcount('queues:'.$queueName.':delayed' , '-inf', '+inf');

Opencart Admin Cron Jobs

I know about CRON and how to create/manage it. But this issue was different.
I want to develop a module to delete any (unpaid) order that exceeds the time frame given.
Ex: I want to delete any unpaid order that has not been paid for 2 days after the order was placed.
I want to use existed model in opencart (and not use a new one). Let's say the module URL would be: http://www.yourstore.com/admin/index.php?route=module/modulename/function
And will be called from CRON, and then all any unpaid order will be disappeared.
But the main problem is: when CRON wants to access that URL, it needs a security token or it will never be executed.
My question is: how to execute that module from CRON without security token (in case just for that module)?
Please help me, if you have a better idea or a more clean way, I would say many thanks to you.
Updated : For Opencart versions <= 1.5.6.4
For admin related cron jobs, Do like this.
Copy the admin/index.php to admin/index_for_cron.php
Now, in the admin/index_for_cron.php, search for these 2 lines and comment them out which are responsible for the login & the permissions.
// Login
// $controller->addPreAction(new Action('common/home/login'));
// Permission
// $controller->addPreAction(new Action('common/home/permission'));
Now use this url for your cron job.
http://www.yourstore.com/admin/index_for_cron.php?route=module/modulename/function
NOTE: it is highly recommended to changes the name of index_for_cron.php into an ugly, unpredictable name for the security reasons.
Hope this helps :)
I've done something similar to IJas. Adjacent to admin and catalog, I've created a new folder called "cli".
This folder contains a php file for a specific function to be performed by cli (executing scripts via crontab on a set schedule, or manually in the command line), as well as a "bootstrap" of sorts for these types of scripts. The bootstrap is essentially a copy of the "index" found in catalog or admin, and includes some checks and removes the permission checking and some other unnecessary items. It calls whatever controller/action is set forth in the calling specific function script (in the example below, it calls the index method of the class defined in /admin/controller/common/cli_some_function.php).
Function-Specific Script:
<?php
$cli_action = 'common/cli_some_function';
require_once('cli_dispatch.php');
?>
CLI "Bootstrap"/Dispatcher:
<?php
// CLI must be called by cli php
if (php_sapi_name() != 'cli') {
syslog(LOG_ERR, "cli $cli_action call attempted by non-cli.");
http_response_code(400);
exit;
}
// Ensure $cli_action is set
if (!isset($cli_action)) {
echo 'ERROR: $cli_action must be set in calling script.';
syslog(LOG_ERR, '$cli_action must be set in calling script');
http_response_code(400);
exit;
}
// Handle errors by writing to log
function cli_error_handler($log_level, $log_text, $error_file, $error_line) {
syslog(LOG_ERR, 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line);
echo 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line;
}
set_error_handler('cli_error_handler');
// Configuration not present in CLI (vs web)
chdir(__DIR__.'/../admin');
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__)) . '../admin/');
$_SERVER['HTTP_HOST'] = '';
// Version
define('VERSION', '1.5.1');
// Configuration (note we're using the admin config)
require_once('../admin/config.php');
// Configuration check
if (!defined('DIR_APPLICATION')) {
echo "ERROR: cli $cli_action call missing configuration.";
$log->write("ERROR: cli $cli_action call missing configuration.");
http_response_code(400);
exit;
}
// Startup
require_once(DIR_SYSTEM . 'startup.php');
// Application Classes
require_once(DIR_SYSTEM . 'library/currency.php');
require_once(DIR_SYSTEM . 'library/user.php');
require_once(DIR_SYSTEM . 'library/weight.php');
require_once(DIR_SYSTEM . 'library/length.php');
// Registry
$registry = new Registry();
// Loader
$loader = new Loader($registry);
$registry->set('load', $loader);
// Config
$config = new Config();
$registry->set('config', $config);
// Database
$db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
$registry->set('db', $db);
// Settings
$query = $db->query("SELECT * FROM " . DB_PREFIX . "setting WHERE store_id = '0'");
foreach ($query->rows as $setting) {
if (!$setting['serialized']) {
$config->set($setting['key'], $setting['value']);
} else {
$config->set($setting['key'], unserialize($setting['value']));
}
}
// Url
$url = new Url(HTTP_SERVER, HTTPS_SERVER);
$registry->set('url', $url);
// Log
$log = new Log($config->get('config_error_filename'));
$registry->set('log', $log);
function error_handler($errno, $errstr, $errfile, $errline) {
global $log, $config;
switch ($errno) {
case E_NOTICE:
case E_USER_NOTICE:
$error = 'Notice';
break;
case E_WARNING:
case E_USER_WARNING:
$error = 'Warning';
break;
case E_ERROR:
case E_USER_ERROR:
$error = 'Fatal Error';
break;
default:
$error = 'Unknown';
break;
}
if ($config->get('config_error_display')) {
echo "\n".'PHP ' . $error . ': ' . $errstr . ' in ' . $errfile . ' on line ' . $errline."\n";
}
if ($config->get('config_error_log')) {
$log->write('PHP ' . $error . ': ' . $errstr . ' in ' . $errfile . ' on line ' . $errline);
}
return true;
}
set_error_handler('error_handler');
$request = new Request();
$registry->set('request', $request);
$response = new Response();
$response->addHeader('Content-Type: text/html; charset=utf-8');
$registry->set('response', $response);
$cache = new Cache();
$registry->set('cache', $cache);
$session = new Session();
$registry->set('session', $session);
$languages = array();
$query = $db->query("SELECT * FROM " . DB_PREFIX . "language");
foreach ($query->rows as $result) {
$languages[$result['code']] = $result;
}
$config->set('config_language_id', $languages[$config->get('config_admin_language')]['language_id']);
$language = new Language($languages[$config->get('config_admin_language')]['directory']);
$language->load($languages[$config->get('config_admin_language')]['filename']);
$registry->set('language', $language);
$document = new Document();
$registry->set('document', $document);
$registry->set('currency', new Currency($registry));
$registry->set('weight', new Weight($registry));
$registry->set('length', new Length($registry));
$registry->set('user', new User($registry));
$controller = new Front($registry);
$action = new Action($cli_action);
$controller->dispatch($action, new Action('error/not_found'));
// Output
$response->output();
?>
Using this scheme, I can ensure the script won't be called from the web, and I can have it fired off automatically from the server itself using a cron job (eg: 0 1 0 0 0 /path/to/php /path/to/opencart/cli/cli_some_function.php)
Note that the error_handler function is using some config options that aren't out-of-the-box. You can either set those up or put your own check there.
EDIT made some changes for the error handling
In 2.3.0.2 a very simple way I found was to add your controller function path into the ignored paths settings for login and permission restrictions. Then just add a url password or other check in that controller function to lock it down.
So first in admin/controller/startup/login.php add your controller function path to both $ignore arrays, eg 'common/cron/action'
And then in admin/controller/startup/permissions.php you want just the controller path, eg 'common/cron'
And then finally at start of your action() function do like:
if(!isset($_GET['pass']) || $_GET['pass'] != 'secretpassword')return;
Then i just added this to my cron:
php-cli -r 'echo file_get_contents("https://www.website.com/admin/index.php?route=common/cron/action&pass=secretpassword");'
As I had a similar requirement several times, I put my ideas into a lightweight commandline tool called OCOK.
Especially the Cli Task Command allows you to call Opencart controllers via the commandline and thus lets you call them as cron jobs. Simply create a controller like this and save it as admin/controller/task/example.php:
class ControllerTaskExample extends Controller {
public function index() {
if (isset($this->is_cli) && $this->is_cli === true) {
// work done by the controller
if (isset($this->request->get['param1'])) {
echo "param1 is " . $this->request->get['param1'] . "\n";
}
if (isset($this->request->get['param2'])) {
echo "param2 is " . $this->request->get['param2'] . "\n";
}
}
}
}
Via the commandline it can be called with parameters:
ocok run task/example param1=foo param2=bar
The above stated command would output:
param1 is foo
param2 is bar
Adding this to crontab is as easy as adding the following line to your cron file:
* * * * * (cd /path/to/opencart/folder; /path/to/ocok run task/example param1=foo param2=bar)
the respective paths need to be set correctly of course.
Installation available with composer. All further documentation can be found inside the docs: OCOK
By default opencart doesn't allow to access admin pages without login. The login and token validations are checked in login() method in admin/controller/common/home.php.
it cant be set on frontend coz the model is in admin area. - You may create a new controller and model for frontend with the same functionality in admin panel and use it for cronjob.
Opencart has got usergroups which sets access rights for the users. So the admin pages will not get loaded for the users without permission. Hence you may need to modify the core files very much for setting cronjob in admin panel which may lead to severe security issues.
I suggest a frontend controller and model file for cronjob. For additional security you can pass a particular key parameter in url and write a condition to verify it.
Have a nice day !!
I know this is a very old question, but I spent quite a long time trying to figure how to do the same in opencart version 2.x which works different. So I share here my solution.(based on Mike T approach)
1 - Create cli folder adjacent to admin and catalog.
2 - In this same folder create a file which you will run via cron or comandline, for example runcron.php
#!/usr/bin/php
<?php
require_once('cli_dispatch.php');
3 - In the same folder create the cli_dispatch.php file which is a copy of the index.php file in admin folder with some changes (Note in this is installation there is VQMOD activated, which may not be your case)
<?php
// CLI must be called by cli php
if (php_sapi_name() != 'cli') {
syslog(LOG_ERR, "cli $cli_action call attempted by non-cli.");
http_response_code(400);
exit;
}
// Ensure $cli_action is set
if (!isset($cli_action)) {
echo 'ERROR: $cli_action must be set in calling script.';
syslog(LOG_ERR, '$cli_action must be set in calling script');
http_response_code(400);
exit;
}
// Handle errors by writing to log
function cli_error_handler($log_level, $log_text, $error_file, $error_line) {
syslog(LOG_ERR, 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line);
echo 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line;
}
set_error_handler('cli_error_handler');
// Configuration (note we're using the admin config)
require_once __DIR__.('/../admin/config.php');
// Configuration not present in CLI (vs web)
chdir(__DIR__.'/../admin');
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__)) . '../admin/');
$_SERVER['HTTP_HOST'] = '';
if (!defined('DIR_APPLICATION')) {
echo "ERROR: cli $cli_action call missing configuration.";
http_response_code(400);
exit;
}
// Version
define('VERSION', '2.3.0.3_rc');
// Configuration
if (is_file('config.php')) {
require_once('config.php');
}
// Install
if (!defined('DIR_APPLICATION')) {
header('Location: ../install/index.php');
exit;
}
//VirtualQMOD
require_once('../vqmod/vqmod.php');
VQMod::bootup();
// VQMODDED Startup
require_once(VQMod::modCheck(DIR_SYSTEM . 'startup.php'));
start('cli');
4 - Now create the file upload/system/config/cli.php which will be the one that opencart will use to read the configuration of your new cli bootrasp from file upload/system/framework.php
<?php
// Site
$_['site_base'] = HTTP_SERVER;
$_['site_ssl'] = HTTPS_SERVER;
// Database
$_['db_autostart'] = true;
$_['db_type'] = DB_DRIVER; // mpdo, mssql, mysql, mysqli or postgre
$_['db_hostname'] = DB_HOSTNAME;
$_['db_username'] = DB_USERNAME;
$_['db_password'] = DB_PASSWORD;
$_['db_database'] = DB_DATABASE;
$_['db_port'] = DB_PORT;
// Session
//$_['session_autostart'] = true;
// Autoload Libraries
$_['library_autoload'] = array(
'openbay'
);
// Actions
$_['action_pre_action'] = array(
'startup/startup',
'startup/error',
'startup/event',
'startup/sass',
// 'startup/login',
// 'startup/permission'
);
// Actions
$_['action_default'] = 'sale/croninvoices';
// Action Events
$_['action_event'] = array(
'view/*/before' => 'event/theme'
);
As you can see there i've commented all the Session and Actions lines related to permissions.
You will ave to edit the line
$_['action_default'] = 'sale/yourscript';
changing 'sale/yourscript' with the path and filename of your controller.
In the example, runnunig the runcron.php file will execute the index funcion in
upload/admin/controller/sale/yourscript.php file
In opencart 2.1.0.2.
If you need db in cron job, but DONT need any opencart models.
You can create file system/mycron/cron_task.php.
And add such code to this file:
// CLI
include_once 'config.php';
include_once DIR_SYSTEM.'library/db/mysqli.php';
include_once DIR_SYSTEM.'helper/general.php';
mb_internal_encoding('UTF-8');
if (php_sapi_name() != 'cli') { error_log('NOT CLI CALL');print 'NOT CLI CALL';http_response_code(400);exit; }
$db = new DB\MySQLi(DB_HOSTNAME,DB_USERNAME,DB_PASSWORD,DB_DATABASE,DB_PORT);
// END CLI
// Your actual code, and you CAN use opencart DB!
foreach ($db->query("SELECT * FROM oc_product")->rows as $row) {
//...
}
Now you can run this from your cron job:
12 7 * * * cd /path/to/opencart/root/folder && php system/mycron/cron_task.php
"I want to develop a module to delete any (unpaid) order that exceed the time frame given. Ex : I want to delete any unpaid order that has not been paid for 2 days after the order was placed."
"I want to use existed model in opencart (and not use a new one)."
So, as I'm sure you know, the problem is that you have to be logged in to the admin to access it's controllers and models, but a cron job will not be logged in when it runs.
You could see if the catalog model will do what you need, in which case no problem:
catalog/model/checkout/order.php
You could follow other answers here - i.e. find some way around logging in.
Or you could just write a stand-alone PHP script that runs a simple SQL query.
You're right that it's usually the correct thing to do to use the models of the system BUT OpenCart is so simple that it should be a pretty simple query (just a few lines) that does what you need so that is also an acceptable option in my opinion in this case.
include_once($_SERVER['DOCUMENT_ROOT'].'/admin/model/module/ModelYourModel.php');
$mym = new ModelYourModel($this->registry);
$mym->yourFunction();
For version 2.1, possibly higher. Use the model from the admin folder in the catalog folder.

How to run a script which uses ZendFramework library from CLI

I intend to run a script using ZendFramework library from CLI.
My script is as following:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Rest_Client');
It can run in a browser, but failed in a command prompt. How can I let the script run from CLI?
Thanks!
this post has some the info you are looking for: Running a Zend Framework action from command line
Below you will find complete functional code that I wrote and use for cron jobs within my apps...
Need to do the following:
pull required files in you cli file
initialize the application and bootstrap resources. Here you can capture cli params and setup request object so it is dispatched properly.
set controller directory
run the application
Here is documentation on Zend_Console_Getopt that will help you understand how to work with cli params.
code for cli.php
<?php
// Define path to application directory
defined('APPLICATION_PATH') || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Define application environment
defined('APPLICATION_ENV') || define('APPLICATION_ENV', 'development');
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/libraries'),
get_include_path(),
)));
// initialize application
require_once 'My/Application/Cron.php';
$application = new My_Application_Cron(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$application->bootstrap();
//
Zend_Controller_Front::getInstance()->setControllerDirectory(APPLICATION_PATH . '/../scripts/controllers');
//
$application->run();
My_Application_Cron class code:
<?php
// because we are extending core application file we have to explicitly require it
// the autoloading occurs in the bootstrap which is part of this class
require_once 'Zend/Application.php';
class My_Application_Cron extends Zend_Application
{
protected $_cliRequest = null;
protected function _bootstrapCliRequest()
{
$this->_isCliBootstapped = true;
try {
$opts = array(
'help|h' => 'Displays usage information.',
'action|a=s' => 'Action to perform in format of module.controller.action',
'params|p=p' => 'URL-encoded parameter list',
//'verbose|v' => 'Verbose messages will be dumped to the default output.',
);
$opts = new Zend_Console_Getopt($opts);
$opts->setOption('ignoreCase', true)
->parse();
} catch (Zend_Console_Getopt_Exception $e) {
exit($e->getMessage() . "\n\n" . $e->getUsageMessage());
}
// See if help needed
if (isset($opts->h)) {
$prog = $_SERVER['argv'][0];
$msg = PHP_EOL
. $opts->getUsageMessage()
. PHP_EOL . PHP_EOL
. 'Examples:' . PHP_EOL
. "php $prog -a index.index'" . PHP_EOL
. "php $prog -a index.index -p 'fname=John&lname=Smith'" . PHP_EOL
. "php $prog -a index.index -p 'name=John+Smith'" . PHP_EOL
. "php $prog -a index.index -p 'name=John%20Smith'" . PHP_EOL
. PHP_EOL;
echo $msg;
exit;
}
// See if controller/action are set
if (isset($opts->a)) {
// Prepare necessary variables
$params = array();
$reqRoute = array_reverse(explode('.', $opts->a));
#list($action, $controller, $module) = $reqRoute;
// check if request parameters were sent
if ($opts->p) {
parse_str($opts->p, $params);
}
//
$this->_cliRequest = new Zend_Controller_Request_Simple($action, $controller, $module);
$this->_cliRequest->setParams($params);
}
}
public function bootstrap($resource = null)
{
$this->_bootstrapCliRequest();
return parent::bootstrap($resource);
}
public function run()
{
// make sure bootstrapCliRequest was executed prior to running the application
if (!($this->_cliRequest instanceof Zend_Controller_Request_Simple)) {
throw new Exception('application required "bootstrapCliRequest"');
}
// set front controller to support CLI
$this->getBootstrap()->getResource('frontcontroller')
->setRequest($this->_cliRequest)
->setResponse(new Zend_Controller_Response_Cli())
->setRouter(new Custom_Controller_Router_Cli())
->throwExceptions(true);
// run the application
parent::run();
}
}
To lean how to run the cli scipt simply type command below in terminal:
#> php /path/to/cli.php -h
Hopefully this will help you and others!

Selenium2 firefox: use the default profile

Selenium2, by default, starts firefox with a fresh profile. I like that for a default, but for some good reasons (access to my bookmarks, saved passwords, use my add-ons, etc.) I want to start with my default profile.
There is supposed to be a property controlling this but I think the docs are out of sync with the source, because as far as I can tell webdriver.firefox.bin is the only one that works. E.g. starting selenium with:
java -jar selenium-server-standalone-2.5.0.jar -Dwebdriver.firefox.bin=not-there
works (i.e. it complains). But this has no effect:
java -jar selenium-server-standalone-2.5.0.jar -Dwebdriver.firefox.profile=default
("default" is the name in profiles.ini, but I've also tried with "Profile0" which is the name of the section in profiles.ini).
I'm using PHPWebdriver (which uses JsonWireProtocol) to access:
$webdriver = new WebDriver("localhost", "4444");
$webdriver->connect("firefox");
I tried doing it from the PHP side:
$webdriver->connect("firefox","",array('profile'=>'default') );
or:
$webdriver->connect("firefox","",array('profile'=>'Profile0') );
with no success (firefox starts, but not using my profile).
I also tried the hacker's approach of creating a batch file:
#!/bin/bash
/usr/bin/firefox -P default
And then starting Selenium with:
java -jar selenium-server-standalone-2.5.0.jar -Dwebdriver.firefox.bin="/usr/local/src/selenium/myfirefox"
Firefox starts, but not using by default profile and, worse, everything hangs: selenium does not seem able to communicate with firefox when started this way.
P.S. I saw Selenium - Custom Firefox profile I tried this:
java -jar selenium-server-standalone-2.5.0.jar -firefoxProfileTemplate "not-there"
And it refuses to run! Excited, thinking I might be on to something, I tried:
java -jar selenium-server-standalone-2.5.0.jar -firefoxProfileTemplate /path/to/0abczyxw.default/
This does nothing. I.e. it still starts with a new profile :-(
Simon Stewart answered this on the mailing list for me.
To summarize his reply: you take your firefox profile, zip it up (zip, not tgz), base64-encode it, then send the whole thing as a /session json request (put the base64 string in the firefox_profile key of the Capabilities object).
An example way to do this on Linux:
cd /your/profile
zip -r profile *
base64 profile.zip > profile.zip.b64
And then if you're using PHPWebDriver when connecting do:
$webdriver->connect("firefox", "", array("firefox_profile" => file_get_contents("/your/profile/profile.zip.b64")))
NOTE: It still won't be my real profile, rather a copy of it. So bookmarks won't be remembered, the cache won't be filled, etc.
Here is the Java equivalent. I am sure there is something similar available in php.
ProfilesIni profile = new ProfilesIni();
FirefoxProfile ffprofile = profile.getProfile("default");
WebDriver driver = new FirefoxDriver(ffprofile);
If you want to additonal extensions you can do something like this as well.
ProfilesIni profile = new ProfilesIni();
FirefoxProfile ffprofile = profile.getProfile("default");
ffprofile.addExtension(new File("path/to/my/firebug.xpi"));
WebDriver driver = new FirefoxDriver(ffprofile);
java -jar selenium-server-standalone-2.21.0.jar -Dwebdriver.firefox.profile=default
should work. the bug is fixed.
Just update your selenium-server.
I was curious about this as well and what I got to work was very simple.
I use the command /Applications/Firefox.app/Contents/MacOS/firefox-bin -P to bring up Profile Manager. After I found which profile I needed to use I used the following code to activate the profile browser = Selenium::WebDriver.for :firefox, :profile => "batman".
This pulled all of my bookmarks and plug-ins that were associated with that profile.
Hope this helps.
From my understanding, it is not possible to use the -Dwebdriver.firefox.profile=<name> command line parameter since it will not be taken into account in your use case because of the current code design. Since I faced the same issue and did not want to upload a profile directory every time a new session is created, I've implemented this patch that introduces a new firefox_profile_name parameter that can be used in the JSON capabilities to target a specific Firefox profile on the remote server. Hope this helps.
I did It in Zend like this:
public function indexAction(){
$appdata = 'C:\Users\randomname\AppData\Roaming\Mozilla\Firefox' . "\\";
$temp = 'C:\Temp\\';
$hash = md5(rand(0, 999999999999999999));
if(!isset($this->params['p'])){
shell_exec("\"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\" -CreateProfile " . $hash);
}else{
$hash = $this->params['p'];
}
$ini = new Zend_Config_Ini('C:\Users\randomname\AppData\Roaming\Mozilla\Firefox\profiles.ini');
$path = false;
foreach ($ini as $key => $value){
if(isset($value->Name) && $value->Name == $hash){
$path = $value->Path;
break;
}
}
if($path === false){
die('<pre>No profile found with name: ' . $hash);
}
echo "<pre>Profile : $hash \nProfile Path : " . $appdata . "$path \n";
echo "Files: \n";
$filesAndDirs = $this->getAllFiles($appdata . $path);
$files = $filesAndDirs[0];
foreach ($files as $file){
echo " $file\n";
}
echo "Dirs : \n";
$dirs = array_reverse($filesAndDirs[1]);
foreach ($dirs as $dir){
echo " $dir\n";
}
echo 'Zipping : ';
$zip = new ZipArchive();
$zipPath = md5($path) . ".temp.zip";
$zipRet = $zip->open($temp .$zipPath, ZipArchive::CREATE);
echo ($zipRet === true)?"Succes\n":"Error $zipRet\n";
echo "Zip name : $zipPath\n";
foreach ($dirs as $dir){
$zipRet = $zip->addEmptyDir($dir);
if(!($zipRet === true) ){
echo "Error creating folder: $dir\n";
}
}
foreach ($files as $file){
$zipRet = $zip->addFile($appdata . $path ."\\". $file,$file);
if(!($zipRet === true && file_exists($appdata . $path . "\\". $file) && is_readable($appdata . $path . "\\". $file))){
echo "Error zipping file: $appdata$path/$file\n";
}
}
$zipRet = $zip->addFile($appdata . $path ."\\prefs.js",'user.js');
if(!($zipRet === true && file_exists($appdata . $path . "\\". $file) && is_readable($appdata . $path . "\\". $file))){
echo "Error zipping file: $appdata$path/$file\n";
}
$zipRet = $zip->close();
echo "Closing zip : " . (($zipRet === true)?("Succes\n"):("Error:\n"));
if($zipRet !== true){
var_dump($zipRet);
}
echo "Reading zip in string\n";
$zipString = file_get_contents($temp .$zipPath);
echo "Encoding zip\n";
$zipString = base64_encode($zipString);
echo $zipString . "\n";
require 'webdriver.php';
echo "Connecting Selenium\n";
$webDriver = new WebDriver("localhost",'4444');
if(!$webDriver->connect("firefox","",array('firefox_profile'=>$zipString))
{
die('Selenium is not running');
}
}
private function getAllFiles($path,$WithPath = false){
$return = array();
$dirs = array();
if (is_dir($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
if(!in_array($file, array('.','..'))){
if(is_dir($path . "\\" . $file)){
$returned = $this->getAllFiles($path . "\\" . $file,(($WithPath==false)?'':$WithPath) . $file . "\\");
$return = array_merge($return,$returned[0]);
$dirs = array_merge($dirs,$returned[1]);
$dirs[] = (($WithPath==false)?'':$WithPath) . $file;
}else{
$return[] = (($WithPath==false)?'':$WithPath) . $file;
}
}
}
closedir($dh);
}
}
return array($return,$dirs);
}
The Idea is that you give in the get/post/zend parameters P with the name of the profile if not a random wil be created, and he will zip all the files put it in the temp folder and put it in.

Categories