I have read many entries and tried a lot (for example, viewhelpers), but unfortunately nothing works (which is definitely due to my little knowledge). We use the Zend Framework 2 internally with CdliTwoStageSignup (https://github.com/cdli/CdliTwoStageSignup). In this module i want to realize that you can only register if a specific date has not been exceeded. This is currently hardcoded, but should now work with a value from the sql database. This value is already used by other modules, but I do not get it in the module CdliTwoStageSignup. Otherwise, nothing is changed on the module. Unfortunately, I have little idea of php and Zend.
hardcoded looks like this: for submission_deadline a date is manually inserted at the moment
this is from module/CdliTwoStageSignup/view/email-verfication/form.phtml
<?php
if (time() < strtotime($this->submission_deadline)) {
print '<h2>Step 1: <small>Email Verification</small></h2>';
} else {
print '<h2>Step 1: <small>Email Verification (disabled)</small></h2>';
}
Because I have little idea of the framework, I searched in other modules and found that in a view/index.phtml:
<?php
//deadlines
if($this->activeSemester){
$submission_deadline = $this->activeSemester->getDtSubmissionDeadline();
}
Can I use that?
This is a public function in /otherModule/Entity/otherModule.php
public function getDtSubmissionDeadline() {
return $this->dtSubmissionDeadline;
}
So in conclusion is my question: How can I use the variable in this module, what is my problem? I have tried solutions from similar issues, but unfortunately nothing worked. If anything is missing, I'll be happy to complete it.
Thank you very much for your help!
I've understood there are several ways to determine the user's home, depending on the platform (mainly Unix/Linux vs Windows).
Composer uses an environment variable, in composer/Platform package:
public static function getUserDirectory()
{
if (false !== ($home = getenv('HOME'))) {
return $home;
}
if (self::isWindows() && false !== ($home = getenv('USERPROFILE'))) {
return $home;
}
if (function_exists('posix_getuid') && function_exists('posix_getpwuid')) {
$info = posix_getpwuid(posix_getuid());
return $info['dir'];
}
throw new \RuntimeException('Could not determine user directory');
}
public static function isWindows()
{
return defined('PHP_WINDOWS_VERSION_BUILD');
}
Webmozart's path-util package uses other environment variables:
public static function getHomeDirectory()
{
// For UNIX support
if (getenv('HOME')) {
return static::canonicalize(getenv('HOME'));
}
// For >= Windows8 support
if (getenv('HOMEDRIVE') && getenv('HOMEPATH')) {
return static::canonicalize(getenv('HOMEDRIVE').getenv('HOMEPATH'));
}
throw new RuntimeException("Your environment or operation system isn't supported");
}
What is the difference between these two methods? Is one more reliable than the other?
Note: I'm using PHP in the CLI, so it's always the actual current user running PHP.
EDIT> I understand that this question seems to ask for an opinion, but it's not the case. I DO NOT KNOW Windows and do not understand why some packages use different ways to determine the user's home directory. I'm asking for explanations about the two mentioned methods: is one of them more reliable than the other and why?
I've edited the title and the question to reflect this precision.
After not working on this for a long time, I finally decided to definitely answer this question.
There are some usefull environment variables defined on Windows: USERPROFILE, APPDATA, LOCALAPPDATA. They are easily accessible via getenv() function:
getenv('USERPROFILE');
USERPROFILE exists on any Windows, according to https://learn.microsoft.com/fr-fr/windows/desktop/shell/knownfolderid
So, on Windows, it seems to be reliable.
If you need to store data for the current user, APPDATA and LOCALAPPDATA are good variables to find that place.
I've written a package to make these tools reusable: https://github.com/Arcesilas/Platform
It's still work in progress and certainly needs to be improved. Any help is welcome to make this tool reliable on any platform.
Thanks to eryksun whose comments helped a lot in solving this question.
So i have been assigned a task that would normally be trivial, but it has to work on a rather old Typo3-Website (4.5). I am very unexperienced with Typo3.
To make an AJAX call, i found out that i need an eID, my own class file, i found out how to call the main function and all that.
Now, i have a lot of configuration in many different locations, and i need to access that information.
In the class.tx_as_es_pi1.php the function main($content, $conf) has this very handy parameter $conf. It seems this is made available by some Typo3 magic. Trying to somehow mimick this behaviour, i have tried this answer, and it provides me with some of the configuration, using these lines:
$conf = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_ases_pi1.'];
var_dump($conf);
I get this result:
'includeLibs' => string 'typo3conf/ext/as_es/pi1/class.tx_as_es_pi1.php' (length=46)
'userFunc' => string 'tx_ases_pi1->main' (length=17)
but the Typoscript Object Browser shows a lot more (including what i need):
[tx_ases_pi1] = USER_INT # TypoScript added by extension "as_es" # Setting as_es plugin TypoScript
[includeLibs] = typo3conf/ext/as_es/pi1/class.tx_as_es_pi1.php
[userFunc] = tx_ases_pi1->main
[config_template] = EXT:as_es/templates/results_elkwue.htm
[config_template_extended] = EXT:as_es/templates/extended_elkwue.htm
[config_searchaccesskey] = someAccessKey
[config_searchproxy] = someProxyUrl
[config_searchfilterurl] = soeSearchFilterUrl
[config_searchshowstat] = 1
[config_utf8decode] = 1
[config_maxtitlelength] = 50
[config_removefromtitle] = SomeString
[config_piwiktracking_host] = somePiwikHost
[config_piwiktracking_port] = 80
[config_piwiktracking_id] = SomeID
[config_fedebug_messages_search] = {$plugin.tx_ases_pi1.configuration.fedebug_messages_search}
So, obvously, there is something i do not really understand here. Could anyone point me in the right direction?
[EDIT] The answer in the related question only provides some of the configuration data, as shown above. I am looking for a hint on how to retrieve the rest of the data.
Okay. I found the answer to this, in this old post.
In the eID - class, add this method:
/**
* Initializes TSFE and sets $GLOBALS['TSFE'].
*
* #return void
*/
protected function initTSFE() {
$GLOBALS['TSFE'] = t3lib_div::makeInstance('tslib_fe',
$GLOBALS['TYPO3_CONF_VARS'], t3lib_div::_GP('id'), '');
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->checkAlternativeIdMethods();
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->getCompressedTCarray();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
// Get linkVars, absRefPrefix, etc
TSpagegen::pagegenInit();
}
and in the main() method, call it: $this->initTSFE(); . Then this call:
$conf = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_ases_pi1.'];
var_dump($conf);
will output the complete list.
I am not claiming i would really understand it... but since it might save others some trouble, i am posting it anyway.
[EDIT]
Apparently it was this line:
$GLOBALS['TSFE']->checkAlternativeIdMethods();
that made the difference. Removing it would result in the short output shown in the question.
As a side note: these lines:
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->getCompressedTCarray();
TSpagegen::pagegenInit();
do not make a difference for me, so i assume that they can be omitted in my case to speed things up a little.I will leave them in here because they might help someone else in the future.
I have a really serious problem that I have not seen before.
On a website we are using opensource SQC eshop, PHP Version 5.3.3-7+squeeze15 and there is some kind of problem with variable memory I think.
SQC uses notORM and here the problem starts with fatal error "Call to function on non object notORMResult" .
So I dug deeper and found the constructor of NotORM that looks like this:
function __construct(PDO $connection, NotORM_Structure $structure = null,NotORM_Cache $cache = null) {
$this->connection = $connection;
if($_GET['test']){
var_dump($structure);
}
if (!isset($structure)) {
$structure = new NotORM_Structure_Convention;
}
if($_GET['test']){
var_dump($structure);
}
$this->structure = $structure;
if($_GET['test']){
var_dump($this->structure);
exit("1");
}
$this->cache = $cache;
}
And so the output is NULL because the constructor gets no structure param so we create an object. Second output is the object. Then we set the object to attribute and then the THIRD OUTPUT IS NULL
How is this even possible? The site was running for about year and half and no problems till yesterday. I didn't made yet any updates to php and this thing really freaks me out 'cause it's not a constant problem. It just happens sometimes after 2 hours, sometimes after 2 mins and I have really no idea why is this happening.
And btw ... this is just the start it happens across the whole script. Object attributes are set but when you want to read them they give you NULL. There is also second website running on the same server, same php same configuration without problem.
Thanks for any ideas :)
I am trying to write a cronjob controller, so I can call one website and have all modules cronjob.php executed. Now my problem is how do I do that?
Would curl be an option, so I also can count the errors and successes?
[Update]
I guess I have not explained it enough.
What I want to do is have one file which I can call like from http://server/cronjob and then make it execute every /application/modules/*/controller/CronjobController.php or have another way of doing it so all the cronjobs aren't at one place but at the same place the module is located. This would offer me the advantage, that if a module does not exist it does not try to run its cronjob.
Now my question is how would you execute all the modules CronjobController or would you do it a completly different way so it still stays modular?
And I want to be able to giveout how many cronjobs ran successfully and how many didn't
After some research and a lot procrastination I came to the simple conclusion that a ZF-ized cron script should contain all the functionality of you zend framework app - without all the view stuff. I accomplished this by creating a new cronjobfoo.php file in my application directory. Then I took the bare minimum from:
-my front controller (index.php)
-my bootstrap.php
I took out all the view stuff and focused on keeping the environment setup, db setup, autoloader, & registry setup. I had to take a little time to correct the document root variable and remove some of the OO functionality copied from my bootstrap.
After that I just coded away.. in my case it was compiling and emailing out nightly reports. It was great to use Zend_Mail. When I was confident that my script was working the way I wanted, I just added it my crontab.
good luck!
For Zend Framework I am currently using the code outlined bellow. The script only includes the portal file index.php, where all the paths, environment and other Zendy code is bootstrapped. By defining a constant in the cron script we cancel the final step , where the application is run.
This means the application is only setup, not even bootstrapped. At this point we start bootstraping the resources we need and that is that
//public/index.php
if(!defined('DONT_RUN_APP') || DONT_RUN_APP == false) {
$application->bootstrap()->run();
}
// application/../cron/cronjob.php
define("DONT_RUN_APP",true);
require(realpath('/srv/www/project/public/index.php'));
$application->bootstrap('config');
$application->bootstrap('db');
//cron code follows
I would caution putting your cronjobs accessible to the public because they could be triggered outside their normal times and, depending on what they do, cause problems (I know that is not what you intend, but by putting them into an actual controller it becomes reachable from the browser). For example, I have one cron that sends e-mails. I would be spammed constantly if someone found the cron URL and just began hitting it.
What I did was make a cron folder and in there created a heartbeat.php which bootstraps Zend Framework (minus MVC) for me. It checks a database which has a list of all the installed cron jobs and, if it is time for them to run, generates an instances of the cron job's class and runs it.
The cron jobs are just child classes from an abstract cron class that has methods like install(), run(), deactivate(), etc.
To fire off my job I just have a simple crontab entry that runs every 5 minutes that hits heartbeat.php. So far it's worked wonderful on two different sites.
Someone mentioned this blog entry a couple days ago on fw-general (a mailinglist which I recommend reading when you use the Zend Framework).
There is also a proposal for Zend_Controller_Request_Cli, which should address this sooner or later.
I have access to a dedicated server and I initially had a different bootstrap for the cron jobs. I eventually hated the idea, just wishing I could do this within the existing MVC setup and not have to bother about moving things around.
I created a file cron.sh, saved is within my site root (not public) and in it I put a series of commands I would like to run. As I wanted to run many commands at once I wrote the PHP within my controllers as usual and added curl calls to those urls within cron.sh. for example curl http://www.mysite.com/cron_controller/action Then on the cron interface I ran bash /path/to/cron.sh.
As pointed out by others your crons can be fired by anyone who guesses the url so there's always that caveat. You can find a solution to that in many different ways.
Take a look at zf-cli:
scripts at master from padraic/ZFPlanet - GitHub
This handles well all cron jobs.
Why not just create a crontab.php, including, or requiring the index.php bootstrap file?
Considering that the bootstrap is executing Zend_Loader::registerAutoload(), you can start working directly with the modules, for instance, myModules_MyClass::doSomething();
That way you are skipping the controllers. The Controller job is to control the access via http. In this case, you don't need the controller approach because you are accessing locally.
Do you have filesystem access to the modules' directories? You could iterate over the directories and determine where a CronjobController.php is available. Then you could either use Zend_Http_Client to access the controller via HTTP or use an approach like Zend_Test_PHPUnit: simulate the actual dispatch process locally.
You could set up a database table to hold references to the cronjob scripts (in your modules), then use a exec command with a return value on pass/fail.
I extended gregor answer with this post. This is what came out:
//public/index.php
// Run application, only if not started from command line (cli)
if (php_sapi_name() != 'cli' || !empty($_SERVER['REMOTE_ADDR'])) {
$application->run();
}
Thanks gregor!
My solution:
curl /cron
Global cron method will include_once all controllers
Check whether each of the controllors has ->cron method
If they have, run those.
Public cron url (for curl) is not a problem, there are many ways to avoid abuse. As said, checking remote IP is the easiest.
This is my way to run Cron Jobs with Zend Framework
In Bootstrap I will keep environment setup as it is minus MVC:
public static function setupEnvironment()
{
...
self::setupFrontController();
self::setupDatabase();
self::setupRoutes();
...
if (PHP_SAPI !== 'cli') {
self::setupView();
self::setupDbCaches();
}
...
}
Also in Bootstrap, I will modify setupRoutes and add a custom route:
public function setupRoutes()
{
...
if (PHP_SAPI == 'cli') {
self::$frontController->setRouter(new App_Router_Cli());
self::$frontController->setRequest(new Zend_Controller_Request_Http());
}
}
App_Router_Cli is a new router type which determines the controller, action, and optional parameters based on this type of request: script.php controller=mail action=send. I found this new router here: Setting up Cron with Zend Framework 1.11
:
class App_Router_Cli extends Zend_Controller_Router_Abstract
{
public function route (Zend_Controller_Request_Abstract $dispatcher)
{
$getopt = new Zend_Console_Getopt (array());
$arguments = $getopt->getRemainingArgs();
$controller = "";
$action = "";
$params = array();
if ($arguments) {
foreach($arguments as $index => $command) {
$details = explode("=", $command);
if($details[0] == "controller") {
$controller = $details[1];
} else if($details[0] == "action") {
$action = $details[1];
} else {
$params[$details[0]] = $details[1];
}
}
if($action == "" || $controller == "") {
die("Missing Controller and Action Arguments == You should have:
php script.php controller=[controllername] action=[action]");
}
$dispatcher->setControllerName($controller);
$dispatcher->setActionName($action);
$dispatcher->setParams($params);
return $dispatcher;
}
echo "Invalid command.\n", exit;
echo "No command given.\n", exit;
}
public function assemble ($userParams, $name = null, $reset = false, $encode = true)
{
throw new Exception("Assemble isnt implemented ", print_r($userParams, true));
}
}
In CronController I do a simple check:
public function sendEmailCliAction()
{
if (PHP_SAPI != 'cli' || !empty($_SERVER['REMOTE_ADDR'])) {
echo "Program cannot be run manually\n";
exit(1);
}
// Each email sent has its status set to 0;
Crontab runs a command of this kind:
* * * * * php /var/www/projectname/public/index.php controller=name action=send-email-cli >> /var/www/projectname/application/data/logs/cron.log
It doesn't make sense to run the bootstrap in the same directory or in cron job folder. I've created a better and easy way to implement the cron job work. Please follow the below things to make your work easy and smart:
Create a cron job folder such as "cron" or "crobjob" etc. whatever you want.
Sometimes we need the cron job to run on a server with different interval like for 1 hr interval or 1-day interval that we can setup on the server.
Create a file in cron job folder like I created an "init.php", Now let's say you want to send a newsletter to users in once per day. You don't need to do the zend code in init.php.
So just set up the curl function in init.php and add the URL of your controller action in that curl function. Because our main purpose is that an action should be called on every day. for example, the URL should be like this:
https://www.example.com/cron/newsletters
So set up this URL in curl function and call this function in init.php in the same file.
In the above link, you can see "cron" is the controller and newsletters is the action where you can do your work, in the same way, don't need to run the bootstrap file etc.