My action is called by WP Cron so I'm trying to prevent it from running twice at the same time. So, I have the following function that uses doing_action function to check if the action is running. Apparently, the code below can't run even when the action is not running. But when I removed the doing_action check, the code runs.
function upload_to_ipfs() {
if ( !doing_action( 'upload_file' ) ) {
//Code to run here
}
}
add_action( 'upload_file', 'upload_to_ipfs' );
You should probably have a look at site transients.
<?php
function so_73821350_get_transient_name() {
return 'so_73821350_transient_name'; // replace this with whatever you want
}
function so_73821350_upload_to_ipfs() {
// get the existing transient
//
// If the transient does not exist, does not have a value, or has expired,
// then the return value will be false.
$process_running = get_site_transient( so_73821350_get_transient_name() );
if ( $process_running ) {
// bail out in case the transient exists and has not expired
// this means the process is still running
return;
}
// set the transient to flag the process as started
// 60 is the time until expiration, in seconds
set_site_transient( so_73821350_get_transient_name(), 1, 60);
// Run the upload process here
upload_function();
// ...
// delete the transient to remove the flag and allow the process to run again
delete_site_transient( so_73821350_get_transient_name() );
}
add_action( 'upload_file', 'so_73821350_upload_to_ipfs' );
docs:
get_site_transient()
set_site_transient()
delete_site_transient()
You're running into a scenario where the code won't run because it's calling !doing_action on itself because the action IS running.
Also,
Wordpress doing_action works by looking at a global PHP variable is all.
This will not work since you're probably not on the same thread process (since a new one is started with every PHP request on most servers).
In which case you'll have to resort to an alternative method for checking.
One such alternative is checking the servers running processes for the action. Take a look at something like this https://write.corbpie.com/check-if-a-process-is-running-on-linux-with-php/ to help guide you in the right direction.
function is_server_doing_action(string $process): bool
{
if (empty(trim(shell_exec("pgrep $process")))) {
return false;
} else {
return true;
}
}
function upload_to_ipfs() {
if ( !is_server_doing_action( 'upload_file' ) ) {
//Code to run here
}
}
add_action( 'upload_file', 'upload_to_ipfs' );
Related
In WordPress, I am creating a plugin where I am sending emails to users. For that, I am using WordPress cron job. So basically what it will do is just send emails to users every hour.
So my code looks like this
public function __construct() {
add_action('init', array( $this, 'send_emails_to_users') );
add_action('cliv_recurring_cron_job', array( $this, 'send_email') );
}
public function send_emails_to_users() {
if(!wp_next_scheduled('cliv_recurring_cron_job')) {
wp_schedule_event (time(), 'hourly', 'cliv_recurring_cron_job');
}
}
public function send_email() {
//send email code goes here
}
Here everything looks good but it does not send the email.
If I make my code like this
public function __construct() {
add_action('head', array( $this, 'send_email') );
}
Then it sends the email. But the problem is here it sends the email on every time the page loads or when the user visits the site.
That's why I want to use wp_schedule_event to make emails every hour.
So can someone tell me how to resolve this issue?
Any suggestions or help will be really appreciated.
First of all ,
1) You need to setup crontab in your server if you want to work dynamically
2) if you want manually wordpress scheduler will call after the page is run
so,
for the crontab setup below is useful link:
crontab
If you want to run your cron in every one hour then you need to add below code:
public function __construct() {
// Call function for cron
add_action('init', array( $this, 'send_emails_to_users') );
}
public function send_emails_to_users() {
if(!wp_next_scheduled('cliv_recurring_cron_job')) {
// Add "cliv_recurring_cron_job" action so it fire every hour
wp_schedule_event(time(), 'hourly', 'cliv_recurring_cron_job');
}
}
add_action('cliv_recurring_cron_job', array( $this, 'send_email') );
public function send_email() {
//send email code goes here
}
for more information see link
Part of my application is a multi-stage checkout process; during the latter pages of this I first run a sanity check on each request to verify the user actually has some items in their basket: if not they're sent back to the beginning.
I have a controller function like this which is called from multiple routes for DRY purposes.
private function checkBasketFull($request)
{
if (self::isBasketEmpty($request)) {
return redirect('/')->with('status', config('app.empty_basket_message'));
}
}
When I call it, I can't just do:
self::checkBasketFull($request);
because without a return the redirect doesn't fire, only the session data is sent.
And I can't do:
return self::checkBasketFull($request);
because that will give an error if there's no redirect or abort the method if checkBasketFull returns anything else.
My current (working) code is:
$check = self::checkBasketFull($request);
if ($check) {
return $check;
}
Is there an alternative way of writing this on a single line, or modifying the checkBasketFull function, so the redirect will occur if the basket is empty but execution will continue as normal if it isn't?
Either use this:
if ($redirect = self::checkBasketFull($request)) return $redirect;
Or throw an error and catch it in the global error handler.
However, instead of returning and checking that for a redirect like that, I'd much rather keep it as two completely separate methods:
public function someRoute(Request $request)
{
if ($this->isBasketEmpty($request)) return $this->redirectBasketEmpty();
// Continue processing this request...
}
protected function isBasketEmpty(request)
{
// run your login here...
}
protected function redirectBasketEmpty()
{
return redirect('/')->with('status', config('app.empty_basket_message'));
}
Feels cleaner to me.
I have the following code:
public function store(Request $request)
{
$this->validateData($request->all());
// store something
return redirect()->action('controller#index')->withMessage( 'Saved Successfully' );
}
private function validateData($requestParams)
{
try
{
$validator->validate( $requestParams );
}
catch ( ValidationException $e )
{
redirect()->action('controller#create')->withInput()->withErrors( $e->get_errors() )->send();
exit(); // this causes the withErrors to not be there
}
}
If I remove the exit();, the error messages will appear, but also the store function will be executed (see // store something). I know I can rewrite my code like:
if($this->validateData($request->all()))
{
// store something
return redirect()->action('controller#index')->withMessage( 'Saved Successfully' );
}
But I don't want the ugly if statement here. There must be a way to redirect with the flash messages without it.
tl;dr
Update your private method code like this to make the redirection work with $errors variable visible:
private function validateData($requestParams)
{
try
{
$validator->validate( $requestParams );
}
catch ( ValidationException $e )
{
$resp = redirect()->action('WelcomeController#index')->withInput()->withErrors($e->get_errors());
\Session::driver()->save();
$resp->send();
exit();
}
}
explaination
When exiting in the middle of your controller, there are some job which is executed in the application termination will not be execute anymore. In your case, the Session middleware terminate method will not be called. Let see its content (ref):
public function terminate($request, $response)
{
if ($this->sessionHandled && $this->sessionConfigured() && ! $this->usingCookieSessions())
{
$this->manager->driver()->save();
}
}
Now, look at the save method of our Session driver (ref)
public function save()
{
$this->addBagDataToSession();
$this->ageFlashData();
$this->handler->write($this->getId(), $this->prepareForStorage(serialize($this->attributes)));
$this->started = false;
}
As you can see, your flash data is only be saved when the Session middleware terminates successfully. With your old code, the flash data will be lost!
What I do with my code is calling the save method manually before sending our response to the browser. However, I still recommend you bring the redirection to the public controller method.
Well I don't see any problem using the if statement there. Basically you do not stop the code execution, so thats why the store function is executed, even if your validation fails. The redirect function just sends a header with the redirect location, it does not abort the code after it to be executed. It works with exit(), because it sends the redirect headers and stop the rest of the code to be exeuted.
This is not ugly, it is clean and clear and I suggest you to use this. This is a good example of right if statement usage - if one conditions i met then do this. In your case if your validation passes, just store the object. (Just remember to modify your validate function to return true or false)
if($this->validateData($request->all()))
{
// store something
return redirect()->action('controller#index')->withMessage( 'Saved Successfully' );
}
The other possible solution is to use try .. catch block like this
public function store(Request $request)
{
try {
$this->validateData($request->all());
// store something
return redirect()->action('controller#index')->withMessage( 'Saved Successfully' );
} catch ( ValidationException $e ) {
return redirect()->action('controller#create')->withInput()->withErrors( $e->get_errors() );
}
}
private function validateData($requestParams)
{
// Your validation logic here
$validator->validate( $requestParams );
}
you just forgot to 'return' after the validation exception :D, then you would not have to 'exit;'
I have a function that I need to timeout and output an error message.
I have found the set_time_limit() function, but I dont think I am using it right.
I have tried...
... some code ...
set_time_limit(12);
$client->sendHttp(URL, TIMEOUT_CONNECT, TIMEOUT_READ);
if (set_time_limit(12) != true){
$_SESSION['Message'] = "Transaction Timed Out!";
}
... some code ...
That's the best I could come up with but it doesn't work. Can you suggest anything?
set_time_limit limits the scripts time, the script all together will end after that amount of time no code will be executed after that
$client->sendHttp should return false, null if a timeout has been reached, read the documentation on that function to see what it will actually return.
Normally if the script timeout, the web server stops it and return an error while You have only a little chance of handling it by Yourself - by defining shutdown function.
But You could use a simple function of Your own, like this one:
function check_timeout($start) {
if(microtime() <= $start + MAX_EXECUTION_TIME)
return true;
return false;
}
while the MAX_EXECUTION_TIME constant would be defined somewhere like
define('MAX_EXECUTION_TIME', 10000); // 10 seconds
Now somewhere in Your code You could do:
// some code...
$start = microtime();
foreach($array as $key => $value) {
if(check_timeout($start)) {
// do something
} else {
// set HTTP header, throw exception, etc.
// return false; // die; // exit;
}
}
Okay, the best way I know to describe the scenario is to first give the example:
Say I have a page called index.php;
At the very top before the <html> tag, one can find;
<?php session_start();
$_SESSION['user_id'] = 1234;
require_once "db.con.php";
?>
Inside that of the <body> tag, one can find:
<div id="div_ajax">
<?php require_once "ajax.php"; ?>
</div>
Now inside the ajax.php page, there is a single button that when clicked will make an ajax request. After the request is made, a simple Db query statement to select user information based on the user_id will be made. The thing is, after the AJAX request, it seems as if the user_id session and the already included Db connection is "lost".
I know I can use a conditional statement to check for AJAX request and just add the lines...
session_start();
require_once "db.con.php";
..at the top of the ajax.php page, but I'm wondering if there's a better way to do this? I don't want to always have to add those two lines to every ajax called PHP page. It sort of defeats the purpose of having the lines on the master page (index.php) to begin with. I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way.
Thanks a lot.
As far as my experience goes, I think your problem can be solved with something called the FrontController pattern.
The basic idea is that you're whole application always calls the same file, index.php for instance (also called the single point of entry).
index.php then performs all the tasks that you need on every single page (like starting the session or including your library classes) and then calls the page you want to requested.
This could look something like this: (Can't test it now)
index.php:
<?php
session_start();
$_SESSION['user_id'] = 1234;
require_once("db.con.php");
if($_REQUEST['Request_Type'] == 'website'){
require_once("header.html");
switch($_REQUEST['Request_Url']){
case 'SomePage':
require('SomePage.php');
break;
case 'SomeOtherPage':
require('SomeOtherPage.php');
break;
default:
require('ajax.php');
}
require_once("footer.html");
}elseif($_REQUEST['Request_Type'] == 'ajax'){
switch($_REQUEST['Ajax_Function']){
case 'ProcessButton':
require('ProcessButton.php');
break;
}
}
?>
ajax.php
echo '<input type="button" onClick="ajaxRequest(\"index.php\",\"ProcessButton\")" Value="ClickMe!" />';
The ajaxRequest() Javascript function would have to send an Ajax Request to index.php setting the parameters
Request_Type = 'ajax'
Ajax_Function = 'ProcessButton'
I don't think that there is a better way, but that doesn't mean that there isn't.
Just a couple of notes from reading your question:
1) Use wrapper files for all of your header information. So, at the beginning of your page, put:
require_once('package.php'); // that's what I call mine
Then in package, I have:
require_once('session.start.php');
require_once('db.con.php');
That way, all your pages are accessing the same thing. If you ever need to change it, it's a lot easier.
There is a speed difference between require_once, include_once, include and require. I don't know how significant it is. Frameworks include like 60+ files when they make a page, so I've always assumed its not too bad.
The session information is stored in a folder on your server. PHP defaults it to /tmp (which you should change to a private folder / not web accessible).
Make sure that you are validating any information sent to the AJAX. Remember that it is just like its own web page, so any permissions or database sensitive information should be protected all the same.
"I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way."
The controller pattern is pretty good for this type of thing. Having a bunch of case statements in one file is hard on your maintenance. When you switch to having files that only have 1 or 2 functions in them, your life will get so much simpler.
Depending on the size of your project, you may want to implement a framework. Check out MVC frameworks. If I don't implement a framework, I still implement a controller pattern.
I lifted this from my blog. What I use now doesn't even look like this, but it started here:
In the Presentation layer, I am determining which elements I want to implement. For each element that I want to implement, I initiate the controller, like so:
$controller = new Controller();
$context = $controller->getContext();
$context->addParam('action', 'login');
$template->setContent( $controller->process() );
I am using the Controller from PHP Objects, Patterns, and Practice 3rd Ed by Matt Zandstra with my own modifications.
Here is what happens:
My presentation layer gets a new controller object.
The Controller object's constructor automatically creates a new CommandContext object.
The CommandContext is automatically going to load up the request variables as a Parameter, so I don't even need to worry about form data until I get to the Logic layer and need to validate and process it.
In the presentation layer, I load up any additional context parameters (or the information that I want to pass on to the controller), including most importantly, the action that I want to be taken by the Controller.
To pass the information on, I call $controller->process(). In the Logic layer, I can use a default "execute" or make a different command. So, in the Presentation layer, I set the action to "Login" which forces the login command and login view pages to open, and the command defaults to execute, but it could be anything.
When I call process, it triggers the CommandFacotry. The CommandFactory is going to first initiate a new Template child object, such as a side bar div box or main body context. It makes this determination with an optional flag that I can pass to the Controller.
The CommandFactory is then going to open up the Command file and pass the template and the context as objects to the Logic layer.
abstract class Command {
}
class CommandContext {
private $params = array();
private $error = "";
function __construct(){
$this->params = $_REQUEST;
}
function addParam( $key, $val ){
$this->params[$key] = $val;
}
function get( $key ){
return $this->params[$key];
}
function issetCheck( $key ){
if( ! empty( $this->params[$key] ) ){
return true;
}
return false;
}
function setError( $error ){
$this->error = $error;
}
function getError(){
return $this->error;
}
}
class CommandNotFoundException extends Exception { }
class CommandFactory {
private static $dir = 'include/classes/command/';
static function getCommand( $action = 'Default', $flag = 0 ){
switch( $flag ){
case 1:
$template = new TemplateQuickViewOnly();
break;
case 2:
$template = new TemplateQuickViewToggle();
break;
default:
$template = new TemplateMainBodyOnly();
break;
}
if( preg_match ( '/\W/', $action ) ){
throw new Exception("illegal characters in action");
}
$class = UCFirst(strtolower($action))."Command";
$file = ROOT_PATH."".self::$dir."{$class}.php";
if( ! file_exists( $file ) ){
throw new CommandNotFoundException( "could not find '$file'" );
}
include_once( $file );
if( ! class_exists($class) ){
throw new CommandNotFoundException( "no '$class' class located" );
}
$cmd = new $class( $template );
return array( $cmd, $template );
}
}
class Controller {
private $context;
function __construct(){
$this->context = new CommandContext();
}
function getContext(){
return $this->context;
}
function process( $method = 'execute', $flag = 0 ){
list( $cmd, $template ) = CommandFactory::getCommand( $this->context->get('action'), $flag );
if( ! $cmd->$method( $this->context ) ){
// handle failure
// $template->setMessage( UCFirst($this->context->get('action')).' failed to execute.');
return $template->getMessage();
}else{
// success dispatch view
return $template->getMessage();
}
}
}
The Logic layer is in a fixed directory. An instance of the object has already been instatiated by the Controller layer, which means the constructor has been triggered. Further, the controller layer already called the method "execute" (default) or another method, such as "getLoginForm". Also, note that when the Controller calls the method "execute", it is also passing the CommandContext to the method so we have stuff to work with.
class LoginCommand extends Command {
public function __construct( ){ }
function execute ( CommandContext $context ){
if( $context->get('login_user_name') == 'demo' ){
$this->view->setMessage('Success is true!');
return true;
}
return false;
}
function getLoginForm( CommandContext $context ){
$this->view->setMessage('Second sucess is even more true!');
return true;
}
}
You seem confused.
AJAX requests are separate requests for a webpage, nothing you did in the index.php on the server side will be available in the subsequent requests (except for any variables in the session). It works like this:
Request is sent for index.php from the browser
Server runs index.php (storing user_id in the session) and returns the HTML output to the browser at the end, the PHP script finishes and all resources are freed.
User clicks on button, creating a new request for another PHP file, say ajax.php
Server runs ajax.php and returns whatever is output to the browser. Again the PHP script finishes and all resources are freed.
Another way to think about this: From the server side, an AJAX request is almost the same as if you'd just pointed your browser to ajax.php directly.