How to run Magento shell script in browser - php

This question has been asked a few times but none of them solves my issue.
I simply created a file:
/shell/test.php
<?php
require_once 'abstract.php';
class Mage_Shell_Test extends Mage_Shell_Abstract
{
public function run() {
echo 'in-shell-test!';
}
}
$shell = new Mage_Shell_Test();
$shell->run();
and commented out $this->_validate(); in
/shell/abstract.php
Then I still see the page of WHOOPS, OUR BAD...
Appreciate any ideas.

You could override the _validate method which is inherited from Mage_Shell_Abstract. This method checks where you are running your script from and it looks like this:
protected function _validate()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
die('This script cannot be run from Browser. This is the shell script.');
}
}
You can change this to return true, but this validation was obviously put there for a reason. If you plan on leaving the script there for a longer period, I would recommend looking for a different approach.

Related

Reusing code in php modules without sharing global namespace

I can't seem to figure out to achieve the following result.
Important: this should work down to php 5.3
Ok, so imagine a situation: you develop a number of php modules, for example WordPress plugins, that are to be run on single setup but do not communicate or know about each other. But some (quite large) parts of codebase are the same and can be reused. How can I achieve the result, when all my modules have "inside of them" this shared library, scoped to each module and not causing conflicts in global space?
For example, see the following:
main.php (some host app, like WordPress)
<?php
require('plugins/first-module/first.php');
require('plugins/second-module/second.php');
$first = new Project1\App();
$first->go();
$second = new Project2\App();
$second->go();
?>
first.php (first module)
<?php
namespace Project1;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
second.php (second module)
<?php
namespace Project2;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
shared.php (shared lib)
<?php
namespace CoreLib\Util\Logger;
class Log {
public function say() {
echo 'It works!';
}
}
Right now I have an error, obviously, because of re-declaring Log class.
Any ideas?

Making phpunit ignore include?

I have a file with a single include like this one:
file.php
include(dirname(__FILE__)."/anotherfile.php");
class file {
function myfunction() {
$class = new anotherfile();
$class->functionfromanotherfile();
}
function myfunctionToBeTested() {
// do things here
}
}
I'm using travis-ci to run my tests with phpunit, and the problem is that I dont commit the "anotherfile.php" (have the logic and credentials to connect to the database), which makes it not work when I try to include this file in my test script.
tests.php
class tests extends PHPUnit_Framework_TestCase {
public function test_function() {
include(dirname(__FILE__)."/file.php");
$class = new file();
}
}
I could make another file with only the function I need to test and go with it but maybe you guys can come up with other awnser.
Use some kind of dependency injection:
Modify the class you want to test so that it accepts the credentials as parameters of the constructor.
In the test, create fake -or real- credentials and pass them to the constructor of your class.

Call exit function from child class in PHP

I have a PHP class where I have to invoke PHP header function to show a webpage. As pointed out from this post, header should be followed by exit callback. Since this situation is very common in my classes, I've defined a method in parent class:
class ParentClass
{
protected function header($url)
{
header('Location:'.$url);
exit;
}
}
I would like to invoke this method from children classes:
class ChildClass extends ParentClass
{
public function someFunc()
{
$this->header($some_url);
}
}
PHP documentation says that exit terminates the current script. My question is: does the exit function terminate child script even if it is contained in parent class?
EDIT
In my specific situation, I am using a MVC design pattern and ChildClass is a controller. Inside it, sometimes I need to show a view, sometimes I need to redirect to another url. Let me explain it with a practical example.
Suppose to have a website with a login section. When login page is displayed to users (login data not submitted), login controller should show login view. This view contains a form with an action like action="login.html". When data is submitted, login controller is invoked and checks login data: if login is successful, user is redirected to his admin section.
class UsersController extends BaseController
{
public function login()
{
try
{
if(isset($_POST['submit']))
{
// check login data, throw exception in case of error
// if success, redirect to admin section
$this->header('admin.html');
}
else
{
// show login view
}
}
catch(Exception $e)
{
// show login view (with error)
}
}
}
class BaseController
{
protected function header($url)
{
header('Location:'.$url);
exit;
}
}
Since this situation is quite common in my controllers, I've preferred to define a header method in BaseController instead of typing everytime
header('Location:someURL.html');
exit;
In my OP, I only wanted to be sure that $this->header('admin.html'); callback would terminate current login method, even if it is defined in BaseController script.
Hope it's a little clearer now.
As already descripted in the comment, exit will terminate everything, i.e. the webpage immediately stops executing, including clean up functions and finally blocks.
So, you should consider using exit very carefully because many things might happen: data doesn't get written to the database when you're not using auto-commit (unless you commit the data before calling exit). Auto-commit is not enabled by default in PHP's MySQL module (as far as I know).
Here is an example:
class B extends A {
public function someFunc() {
# you might wanna use partent instead as
# pointed out by Ding in the comments, but
# maybe someFunc does more that just doing
# the redirect.
$this->header("http://google.com");
}
}
try {
print("Ok...");
$obj = new B();
$obj->someFunc();
print("Nahh..."); # doesn't get called/
} finally {
print("Cleaning up."); # doesn't get called, either.
}
Instead of calling the exit method, you should rather implement a clear MVC design pattern. Here is a very quick example:
<?php
class Response {
# use private here and use appropriate
# getters and setters.
public $status_code = 200;
public $content = "";
public $headers = array();
}
class HomeView extends View {
# called when a get request is made.
public function get() {
$response = new Response();
$response->content = "Hello world."
}
}
class RedirectionView {
public function get() {
$response = new Response();
$response->status_code = 301; # use 302 if moved only temporarily.
$response->headers["Location"] = "http://google.com";
}
}
function processRequest() {
# load appropriate view programatically
$view = new RedirectionView();
$response = $view->get();
http_response_code($response->status_code);
foreach ($response->headers as $headerName => $headerValue) {
header(sprintf("%s: %s", $headerName, $headerValue));
}
print($view->content)
}
?>
Note that this is not really a MVC design pattern (the model is missing and, well, it's not clear what the controller, however, that's what django (a Pyhton framework) uses, too). You might wanna check out PHP MVC frameworks (a quick google search will do the trick) or implement your own (my example might be a good start).
Edit 1:
Using exit is probably ok (but I wouldn't use it because I believe it is bad practice). If you're able to edit the design approach you're using, I'd make your View BaseClass get/post method (or whatever you're the method that returns response object. Note: if you're using prints to show the response to the user, try to add a Response which contains all the data you're request needs to show. This is better than having prints (or echos) everywhere in your code).
Using the response object, your code would then be able to either just set the location header (if it's a redirect) or show the message. So you don't need to "kill" any part of the webpage and it will terminal when the execution ends. But again: you're probably good to go with an exit call in your method (unless you're encountering any issues with your code (database transactions that aren't committed, statistic data that is not updated (because its after the exit statement). Exit will simply terminate your script completely.

PHP Class not found while it's included

I have a problem with classes which cannot be found in PHP.
The first thing I do is 'require_once' a file which 'require_once's all other files. When loading, no problems are showed. But when I start calling my function (Users::verificate();) I get the following error:
Fatal error: Class 'Users' not found in /Applications/XAMPP/xamppfiles/htdocs/sparks/dashboard.php on line 4
To test I've added a simple class with a function which only outputs a string with the echo method. This works so the problem has to be with this class. A MySql function which I call like this just works.
$mySql = new MySql();
$mySql->executeQuery('...');
The simple class has static a static function which I call like this (Oh, this works):
simple::launch();
In the Users class I'm calling non static functions from the MySql class from a static function. Can this be the problem?
Like another question here on SO suggested the problem isn't in using short php opening tags instead of the traditional php opening tag.
Even a little hint may help me :). Thanks for your time!
Edit:
I've added some relevant code from the User class. This is basically what it all looks like:
<?php
class Users {
public static function authenticate($email, $password) {
$mySql = new MySql();
$mySqlResult = $mySql->executeQuery("selectUser", [$email]);
...
}
public static function isAdmin() {
if ($_SESSION['isAdmin']) {
return true;
}
return false;
}
...
}
Edit 2:
I'm trying to show the flow:
From dashboard.php this are the first code lines:
<?php
require_once('code/init.php');
simple::launch();
if (!Users::verify()) {
header("Location: index.php");
}
?>
simple::launch(); is the code I used to test. This executes well. From this on the init.php file looks like this:
<?php
session_start();
require_once('simple.php');
require_once('MySql.php');
require_once('Users.php');
require_once('Projects.php');
The file names are correct as I get a visible error when these are wrong.
dashboard.php exists in the root. From there is a folder called 'code' which contains all these files.
#MbRostami gave the advice in a comment to use the 'get_required_files()' function to see which files are included. It turns out that the wrong files were loaded.
Root
| dashboard.php
| users.php
|- code
| Users.php
| init.php
In the init.php file the Users.php file (both files are in the code folder) was required. But for some reason the users.php file from the root was loaded. Some strange behaviour imho. Ahwell, that's something to investigate during the christmas days.
Problem is solved! Thanks!

Execute a Function in Silverstripe via Cronjob

Hi I want to execute a function via cronjob to start an csv import. At the moment the import is triggered by accessing a controller in the browser tld.de/Update
The controller has this code http://pastie.org/8351266
How can I execute the function init() via Cronjob?
Thx!
In SilverStripe you can access any route that is accessible via HTTP also by running cli-script.php in the command line
There also is sake which is just a bash wrapper around cli-script.php (but sake needs to be installed)
so, from your project directory, you can run both commands which will perform the same action (in this case, run a dev/build):
php framework/cli-script.php dev/build
sake dev/build
see the docs for commandline ussage of silverstripe: http://doc.silverstripe.org/framework/en/topics/commandline
the 2nd part of your question (how to call a method from a controller) is actually more a question of routing in silverstripe and has nothing to do with how it is called (cronjob)
I assume that your controller is a Page_Controller or a subclass of that (so bound to a SiteTree Model), then routing is done for you (it takes the URLs you set in the CMS).
so lets see some example code and lets assume you have a page with the URLSegment about:
class Page_Controller extends ContentController {
private static $allowed_actions = array('something');
public function init() {
// the init method will run before every action
// this means this code will run, no matter if you visit /about or /about/something
}
public function index() {
// this is the default action (this code is optional and can be removed),
// and will be called if you visit website.com/about
return $this;
}
public function something() {
// this is the somethingaction,
// and will be called if you visit website.com/about/something
// do something here
return $this;
}
}
you can then call run to get the result of the index():
php framework/cli-script.php about
and this to get the result of something():
php framework/cli-script.php about/something
NOTE: the init method itself is not accessable via URL, it is the "setup" that runs before an action
NOTE: all actions other than index() have to be allowed by adding them to $allowed_actions (also note that you need to ?flush=1 after adding to $allowed_actions to reload the config cache)
EDIT: this was actually the response to your first question, after seeing your code example, this addition:
for standalone controllers it works the same way, just that you have to define the routes, and make sure that you have $Action in the route so that something() can be called
You could do this without Silverstripe sake. Install curl and call the URL via a cronjob, ie:
0 0 * * * curl --silent http://tld.de/Update
The proper way to do this would be to write a Silverstripe task, and invoke your controller from within the task. I haven't tested this code but it would go something like this:
class YourTask extends BuildTask {
public $description = "...";
//...
public function run($request) {
YourController::init();
}
}
You can invoke it over sake using:
0 0 * * * /path/to/framework/sake dev/tasks/YourTask
why not create a build task ? which is specially designed for such requirements (at-least that's how I consider build tasks)
<?php
class ArticleCsvUpdateTask extends BuildTask {
protected $title = 'Article Csv Update';
protected $description = 'Build task for article Csv update';
public function run($request) {
$loader = new ArticleCsvBulkLoader('Color');
if($loader->load('import-new.csv')) {
$loader->load('import-new.csv');
}
}
}
Which can be assess both from browser using "yoursite/dev/tasks/ArticleCsvUpdateTask" and from command line using "php framework/cli-script.php dev/tasks/ArticleCsvUpdateTask" OR using "sake dev/tasks/ArticleCsvUpdateTask" (if you have sake installed).
May be I am not getting your exact requirement but I believe this is much cleaner and nicer way of running a cron job with silverstripe.
See Zauberfisch's answer for a complete solution
I'm not familiar with Silverstripe, but if I understand correctly, this controller init function can be called with a HTTP request.
As the silverstripe docs say, you can call any url from the command line:
php framework/cli-script.php Update/init
More information is available here, and consider using sake for this task.
I think the right way do this is create a php file console like:
#!/usr/bin/env php
<?php
require_once "/path/to/your/class/Update.php";
$class = new Update();
$class->init();
Add right perms to this file
chmod 755 consolefile
And finally run this script with cronjob

Categories