Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
<?php
/**
* @brief advertStats Task
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 03 Apr 2023
*/
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
use IPS\Db;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Task;
use IPS\Task\Exception;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* advertStats Task
*/
class advertStats extends Task
{
/**
* Execute
*
* If ran successfully, should return anything worth logging. Only log something
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws Exception
*/
public function execute() : mixed
{
$inserts = [];
$time = time();
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'core_advertisements' ), '\IPS\core\Advertisement' ) as $advert )
{
$inserts[] = [
'type' => 'advert',
'value_1' => $advert->id,
'value_2' => $advert->daily_impressions,
'value_3' => $advert->daily_clicks,
'time' => $time
];
}
if( count( $inserts ) )
{
Db::i()->insert( 'core_statistics', $inserts );
}
Db::i()->update( 'core_advertisements', [ 'ad_daily_impressions' => 0, 'ad_daily_clicks' => 0 ] );
return NULL;
}
/**
* Cleanup
*
* If your task takes longer than 15 minutes to run, this method
* will be called before execute(). Use it to clean up anything which
* may not have been done
*
* @return void
*/
public function cleanup() : void
{
}
}
+41 -26
View File
@@ -11,16 +11,31 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Application;
use IPS\Content\Comment;
use IPS\core\Reports\Report;
use IPS\core\Reports\Rules;
use IPS\Db;
use IPS\Member;
use IPS\Notification;
use IPS\Settings;
use IPS\Task;
use OutofRangeException;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* automaticmoderation Task
*/
class _automaticmoderation extends \IPS\Task
class automaticmoderation extends Task
{
/**
* Execute
@@ -31,26 +46,26 @@ class _automaticmoderation extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
if ( ! \IPS\Settings::i()->automoderation_enabled )
if ( ! Settings::i()->automoderation_enabled )
{
return NULL;
}
foreach( \IPS\Db::i()->select( '*', 'core_automatic_moderation_pending', NULL, 'pending_added ASC', array( 0, 50 ) ) as $pending )
foreach( Db::i()->select( '*', 'core_automatic_moderation_pending', NULL, 'pending_added ASC', array( 0, 50 ) ) as $pending )
{
/* Check report exists still */
try
{
$report = \IPS\core\Reports\Report::load( $pending['pending_report_id'] );
$report = Report::load( $pending['pending_report_id'] );
}
catch( \OutofRangeException $e )
catch( OutofRangeException $e )
{
/* Report is missing */
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_report_id=?', $pending['pending_report_id'] ) );
Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_report_id=?', $pending['pending_report_id'] ) );
continue;
}
@@ -61,22 +76,22 @@ class _automaticmoderation extends \IPS\Task
{
$object = $className::load( $pending['pending_object_id'] );
}
catch( \OutofRangeException $e )
catch( OutofRangeException $e )
{
/* Object no longer exists */
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
continue;
}
/* Check rule exists still */
try
{
$rule = \IPS\core\Reports\Rules::load( $pending['pending_rule_id'] );
$rule = Rules::load( $pending['pending_rule_id'] );
}
catch( \OutofRangeException $e )
catch( OutofRangeException $e )
{
/* Rule no longer exists */
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_rule_id=?', $pending['pending_rule_id'] ) );
Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_rule_id=?', $pending['pending_rule_id'] ) );
continue;
}
@@ -84,30 +99,30 @@ class _automaticmoderation extends \IPS\Task
$hidden = FALSE;
try
{
if ( $object instanceof \IPS\Content\Comment )
if ( $object instanceof Comment )
{
$item = $object->item();
if ( $item and $item::$firstCommentRequired and $object->isFirst() )
{
/* Hide the item, not the object */
$item->hide( FALSE, \IPS\core\Reports\Rules::getDefaultHideReason() );
$item->hide( FALSE, Rules::getDefaultHideReason() );
$hidden = TRUE;
}
}
}
catch( \Exception $e ) { }
catch( Exception $e ) { }
if ( $hidden === FALSE )
{
$object->hide( FALSE, \IPS\core\Reports\Rules::getDefaultHideReason() );
$object->hide( FALSE, Rules::getDefaultHideReason() );
}
/* Remove from the pending queue */
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
/* Send notification to mods */
$moderators = array( 'm' => array(), 'g' => array() );
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
foreach ( Db::i()->select( '*', 'core_moderators' ) as $mod )
{
$canView = FALSE;
if ( $mod['perms'] == '*' )
@@ -131,16 +146,16 @@ class _automaticmoderation extends \IPS\Task
try
{
$latestReport = \IPS\Db::i()->select( '*', 'core_rc_reports', array( 'rid=?', $report->id ), 'date_reported DESC' )->first();
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'automatic_moderation', $report, array( $report, $latestReport, $object ) );
foreach ( \IPS\Db::i()->select( '*', 'core_members', ( \count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $member )
$latestReport = Db::i()->select( '*', 'core_rc_reports', array( 'rid=?', $report->id ), 'date_reported DESC' )->first();
$notification = new Notification( Application::load('core'), 'automatic_moderation', $report, array( $report, $latestReport, $object ) );
foreach ( Db::i()->select( '*', 'core_members', ( count( $moderators['m'] ) ? Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $member )
{
$notification->recipients->attach( \IPS\Member::constructFromData( $member ) );
$notification->recipients->attach( Member::constructFromData( $member ) );
}
$notification->send();
}
catch( \Exception $e ) { }
catch( Exception $e ) { }
}
return NULL;
+17 -9
View File
@@ -11,16 +11,24 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DirectoryIterator;
use IPS\File;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
use function is_dir;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* chunkcleanup Task
*/
class _chunkcleanup extends \IPS\Task
class chunkcleanup extends Task
{
/**
* Execute
@@ -31,26 +39,26 @@ class _chunkcleanup extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$chunksCleanedUp = 0;
/* Loop over file storage configurations */
foreach( \IPS\File::getStore() as $configuration )
foreach( File::getStore() as $configuration )
{
/* If this is a filesystem config... */
if( $configuration['method'] == 'FileSystem' )
{
/* Get the configuration object */
$fileStorageObject = \IPS\File::getClass( $configuration['id'] );
$fileStorageObject = File::getClass( $configuration['id'] );
/* If we have a chunks folder */
if( \is_dir( $fileStorageObject->configuration['dir'] . '/chunks' ) )
if( is_dir( $fileStorageObject->configuration['dir'] . '/chunks' ) )
{
/* Loop over all the files in the directory */
$iterator = new \DirectoryIterator( $fileStorageObject->configuration['dir'] . '/chunks' );
$iterator = new DirectoryIterator( $fileStorageObject->configuration['dir'] . '/chunks' );
foreach( $iterator as $file )
{
+121 -110
View File
@@ -10,45 +10,59 @@
namespace IPS\core\tasks;
use IPS\Application;
use function implode;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\Application;
use IPS\Content;
use IPS\core\AdminNotification;
use IPS\DateTime;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
use IPS\Task;
use IPS\Widget;
use OutOfRangeException;
use RuntimeException;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Daily Cleanup Task
*/
class _cleanup extends \IPS\Task
class cleanup extends Task
{
/**
* Execute
*
* @return mixed Message to log or NULL
* @throws \RuntimeException
* @throws RuntimeException
*/
public function execute()
public function execute() : mixed
{
/* Delete old failed guest logins for accounts that do not exist */
if( $maxCutoff = (int) \IPS\Settings::i()->bruteforce_global_period )
if( $maxCutoff = (int) Settings::i()->bruteforce_global_period )
{
\IPS\Db::i()->delete( 'core_login_failures', [
Db::i()->delete( 'core_login_failures', [
'login_date<? AND login_ip_address IS NOT NULL AND login_email IS NOT NULL',
( new \IPS\DateTime )->sub( new \DateInterval( 'PT' . $maxCutoff . 'M' ) )->sub( new \DateInterval( 'PT24H' ) )->getTimestamp()
( new DateTime )->sub( new DateInterval( 'PT' . $maxCutoff . 'M' ) )->sub( new DateInterval( 'PT24H' ) )->getTimestamp()
] );
}
/* Delete old password / security answer reset requests */
\IPS\Db::i()->delete( 'core_validating', array( '( lost_pass=1 OR forgot_security=1 ) AND email_sent < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_validating', array( '( lost_pass=1 OR forgot_security=1 ) AND email_sent < ?', DateTime::create()->sub( new DateInterval( 'P1D' ) )->getTimestamp() ) );
/* If we are currently pruning any large tables via a bg task, find out so we don't try to prune them normally here as well. The bg task should finish first. */
$currentlyPruning = array();
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( '`key`=?', 'PruneLargeTable' ) ) as $pruneTask )
foreach( Db::i()->select( '*', 'core_queue', array( '`key`=?', 'PruneLargeTable' ) ) as $pruneTask )
{
$data = json_decode( $pruneTask['data'], true );
@@ -56,13 +70,13 @@ class _cleanup extends \IPS\Task
}
/* Delete old validating members */
if ( \IPS\Settings::i()->validate_day_prune )
if ( Settings::i()->validate_day_prune )
{
$select = \IPS\Db::i()->select( 'core_validating.member_id, core_members.member_posts', 'core_validating', array( 'core_validating.new_reg=1 AND core_validating.coppa_user<>1 AND core_validating.entry_date<? AND core_validating.lost_pass<>1 AND core_validating.user_verified=0 AND !(core_members.members_bitoptions2 & 16384 ) AND core_members.member_posts < 1 AND core_validating.do_not_delete=0', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->validate_day_prune . 'D' ) )->getTimestamp() ) )->join( 'core_members', 'core_members.member_id=core_validating.member_id' );
$select = Db::i()->select( 'core_validating.member_id, core_members.member_posts', 'core_validating', array( 'core_validating.new_reg=1 AND core_validating.coppa_user<>1 AND core_validating.entry_date<? AND core_validating.lost_pass<>1 AND core_validating.user_verified=0 AND !(core_members.members_bitoptions2 & 16384 ) AND core_members.member_posts < 1 AND core_validating.do_not_delete=0', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->validate_day_prune . 'D' ) )->getTimestamp() ) )->join( 'core_members', 'core_members.member_id=core_validating.member_id' );
foreach ( $select as $row )
{
$member = \IPS\Member::load( $row['member_id'] );
$member = Member::load( $row['member_id'] );
if( $member->member_id )
{
@@ -70,189 +84,189 @@ class _cleanup extends \IPS\Task
}
else
{
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=?', $row['member_id'] ) );
Db::i()->delete( 'core_validating', array( 'member_id=?', $row['member_id'] ) );
}
}
}
/* Delete file system logs */
if( \IPS\Settings::i()->file_log_pruning )
if( Settings::i()->file_log_pruning )
{
\IPS\Db::i()->delete( 'core_file_logs', array( 'log_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->file_log_pruning . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_file_logs', array( 'log_date < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->file_log_pruning . 'D' ) )->getTimestamp() ) );
}
/* Delete edit history past prune date */
if( \IPS\Settings::i()->edit_log_prune > 0 )
if( Settings::i()->edit_log_prune > 0 )
{
\IPS\Db::i()->delete( 'core_edit_history', array( 'time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->edit_log_prune . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_edit_history', array( 'time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->edit_log_prune . 'D' ) )->getTimestamp() ) );
}
/* Delete task logs older than the prune-since date */
if( \IPS\Settings::i()->prune_log_tasks )
if( Settings::i()->prune_log_tasks )
{
\IPS\Db::i()->delete( 'core_tasks_log', array( 'time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_tasks . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_tasks_log', array( 'time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_tasks . 'D' ) )->getTimestamp() ) );
}
/* Delete email error logs older than the prune-since date */
if( \IPS\Settings::i()->prune_log_email_error )
if( Settings::i()->prune_log_email_error )
{
\IPS\Db::i()->delete( 'core_mail_error_logs', array( 'mlog_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_email_error . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_mail_error_logs', array( 'mlog_date < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_email_error . 'D' ) )->getTimestamp() ) );
}
/* ...and admin logs */
if( \IPS\Settings::i()->prune_log_admin )
if( Settings::i()->prune_log_admin )
{
\IPS\Db::i()->delete( 'core_admin_logs', array( 'ctime < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_admin . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_admin_logs', array( 'ctime < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_admin . 'D' ) )->getTimestamp() ) );
}
/* ...and moderators logs */
if( \IPS\Settings::i()->prune_log_moderator )
if( Settings::i()->prune_log_moderator )
{
\IPS\Db::i()->delete( 'core_moderator_logs', array( 'ctime < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_moderator . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_moderator_logs', array( 'ctime < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_moderator . 'D' ) )->getTimestamp() ) );
}
/* ...and error logs */
if( \IPS\Settings::i()->prune_log_error )
if( Settings::i()->prune_log_error )
{
\IPS\Db::i()->delete( 'core_error_logs', array( 'log_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_error . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_error_logs', array( 'log_date < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_error . 'D' ) )->getTimestamp() ) );
/* If we don't have any logs left, remove any notifications */
if( \IPS\Db::i()->select( 'count(log_id)', 'core_error_logs' )->first() === 0 )
if( Db::i()->select( 'count(log_id)', 'core_error_logs' )->first() === 0 )
{
\IPS\core\AdminNotification::remove( 'core', 'Error' );
AdminNotification::remove( 'core', 'Error' );
}
}
/* ...and spam service logs */
if( \IPS\Settings::i()->prune_log_spam )
if( Settings::i()->prune_log_spam )
{
\IPS\Db::i()->delete( 'core_spam_service_log', array( 'log_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_spam . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_spam_service_log', array( 'log_date < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_spam . 'D' ) )->getTimestamp() ) );
}
/* ...and admin login logs */
if( \IPS\Settings::i()->prune_log_adminlogin )
if( Settings::i()->prune_log_adminlogin )
{
\IPS\Db::i()->delete( 'core_admin_login_logs', array( 'admin_time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_adminlogin . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_admin_login_logs', array( 'admin_time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_adminlogin . 'D' ) )->getTimestamp() ) );
}
/* ...and statistics */
if( \IPS\Settings::i()->stats_online_users_prune )
if( Settings::i()->stats_online_users_prune )
{
\IPS\Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'online_users', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_online_users_prune . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'online_users', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->stats_online_users_prune . 'D' ) )->getTimestamp() ) );
}
if( \IPS\Settings::i()->stats_keywords_prune )
if( Settings::i()->stats_keywords_prune )
{
\IPS\Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'keyword', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_keywords_prune . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'keyword', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->stats_keywords_prune . 'D' ) )->getTimestamp() ) );
}
if( \IPS\Settings::i()->stats_search_prune )
if( Settings::i()->stats_search_prune )
{
\IPS\Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'search', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_search_prune . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_statistics', array( 'type=? AND time < ?', 'search', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->stats_search_prune . 'D' ) )->getTimestamp() ) );
}
if( \IPS\Settings::i()->prune_log_emailstats > 0 )
if( Settings::i()->prune_log_emailstats > 0 )
{
\IPS\Db::i()->delete( 'core_statistics', array( "type IN('emails_sent','email_views','email_clicks') AND time < ?", \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_emailstats . 'D' ) )->getTimestamp() ) );
}
/* ...and guest details stored with reports */
if( (int) \IPS\Settings::i()->report_guest_details_store_days > 0 )
{
\IPS\Db::i()->update( 'core_rc_reports', [ 'guest_name' => null, 'guest_email' => null ], array( 'date_reported < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->report_guest_details_store_days . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_statistics', array( "type IN('emails_sent','email_views','email_clicks') AND time < ?", DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_log_emailstats . 'D' ) )->getTimestamp() ) );
}
/* ...and geoip cache */
\IPS\Db::i()->delete( 'core_geoip_cache', array( 'date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P7D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_geoip_cache', array( 'date < ?', DateTime::create()->sub( new DateInterval( 'P7D' ) )->getTimestamp() ) );
/* ...and API logs */
$successfulCodes = [ 200, 201, 202, 203, 204, 205, 206, 207, 208, 226 ];
if( \IPS\Settings::i()->api_log_prune )
if( Settings::i()->api_log_prune )
{
\IPS\Db::i()->delete( 'core_api_logs', array( 'date < ? and response_code IN(' . implode( ',', $successfulCodes ) . ')', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->api_log_prune . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_api_logs', array( 'date < ? and response_code IN(' . implode( ',', $successfulCodes ) . ')', DateTime::create()->sub( new \DateInterval( 'P' . Settings::i()->api_log_prune . 'D' ) )->getTimestamp() ) );
}
if( \IPS\Settings::i()->api_log_prune_failures )
if( Settings::i()->api_log_prune_failures )
{
\IPS\Db::i()->delete( 'core_api_logs', array( 'date < ? and response_code NOT IN(' . implode( ',', $successfulCodes ) . ')', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->api_log_prune_failures . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_api_logs', array( 'date < ? and response_code NOT IN(' . implode( ',', $successfulCodes ) . ')', DateTime::create()->sub( new \DateInterval( 'P' . Settings::i()->api_log_prune_failures . 'D' ) )->getTimestamp() ) );
}
/* ...and non-nexus member history */
if( \IPS\Settings::i()->prune_member_history AND !\in_array( 'core_member_history', $currentlyPruning ) )
/* ...and non-member history */
if( Settings::i()->prune_member_history AND !in_array( 'core_member_history', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_member_history', array( 'log_date < ? and log_app != ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_member_history . 'D' ) )->getTimestamp(), 'nexus' ) );
Db::i()->delete( 'core_member_history', array( 'log_date < ? and log_app != ?', DateTime::create()->sub( new \DateInterval( 'P' . Settings::i()->prune_member_history . 'D' ) )->getTimestamp(), 'nexus' ) );
}
/* ...and Nexus member history */
if( Application::appIsEnabled('nexus') and \IPS\Settings::i()->nexus_prune_history AND !\in_array( 'core_member_history', $currentlyPruning ) )
if( Application::appIsEnabled('nexus') and Settings::i()->nexus_prune_history AND !\in_array( 'core_member_history', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_member_history', array( 'log_date < ? and log_app = ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->nexus_prune_history . 'D' ) )->getTimestamp(), 'nexus' ) );
Db::i()->delete( 'core_member_history', array( 'log_date < ? and log_app = ?', DateTime::create()->sub( new \DateInterval( 'P' . Settings::i()->nexus_prune_history . 'D' ) )->getTimestamp(), 'nexus' ) );
}
/* ...and promote response logs */
\IPS\Db::i()->delete( 'core_social_promote_content', array( 'response_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P6M' ) )->getTimestamp() ) );
/* ...and webhook logs */
if( \IPS\Settings::i()->webhook_logs_success )
if( Settings::i()->webhook_logs_success )
{
\IPS\Db::i()->delete( 'core_api_webhook_fires', array( "status='successful' AND time < ?", \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->webhook_logs_success . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_api_webhook_fires', array( "status='successful' AND time < ?", DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->webhook_logs_success . 'D' ) )->getTimestamp() ) );
}
if( \IPS\Settings::i()->webhook_logs_fail )
if( Settings::i()->webhook_logs_fail )
{
\IPS\Db::i()->delete( 'core_api_webhook_fires', array( "status='failed' AND time < ?", \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->webhook_logs_fail . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_api_webhook_fires', array( "status='failed' AND time < ?", DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->webhook_logs_fail . 'D' ) )->getTimestamp() ) );
}
/* ...and points log */
if( \IPS\Settings::i()->prune_points_log )
if( Settings::i()->prune_points_log )
{
\IPS\Db::i()->delete( 'core_achievements_log', array( 'datetime < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_points_log . 'D' ) )->getTimestamp() ) );
\IPS\Db::i()->delete( 'core_points_log', array( 'datetime < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_points_log . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_achievements_log', array( 'datetime < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_points_log . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_points_log', array( 'datetime < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_points_log . 'D' ) )->getTimestamp() ) );
}
/* Delete old notifications */
if ( \IPS\Settings::i()->prune_notifications )
if ( Settings::i()->prune_notifications )
{
$memberIds = array();
foreach( \IPS\Db::i()->select( '`member`', 'core_notifications', array( 'sent_time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_notifications . 'D' ) )->getTimestamp() ) ) as $member )
foreach( Db::i()->select( '`member`', 'core_notifications', array( 'sent_time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_notifications . 'D' ) )->getTimestamp() ) ) as $member )
{
$memberIds[ $member ] = $member;
}
\IPS\Db::i()->delete( 'core_notifications', array( 'sent_time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_notifications . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_notifications', array( 'sent_time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_notifications . 'D' ) )->getTimestamp() ) );
foreach( $memberIds as $member )
{
\IPS\Member::load( $member )->recountNotifications();
Member::load( $member )->recountNotifications();
}
}
/* Delete old item markers */
if ( \IPS\Settings::i()->prune_item_markers AND !\in_array( 'core_item_markers', $currentlyPruning ) )
/* Delete old follows */
if ( Settings::i()->prune_follows AND !in_array( 'core_follow', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_item_markers', array( 'item_member_id IN(?)', \IPS\Db::i()->select( 'member_id', 'core_members', array( 'last_activity < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_item_markers . 'D' ) )->getTimestamp() ) ) ) );
Db::i()->delete( 'core_follow', array( 'follow_app!=? AND follow_area!=? AND follow_member_id IN(?)', 'core', 'member', Db::i()->select( 'member_id', 'core_members', array( 'last_activity < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_follows . 'D' ) )->getTimestamp() ) ) ) );
/* And clear the cache so it can rebuild */
Db::i()->delete( 'core_follow_count_cache' );
}
/* Delete old item markers */
if ( Settings::i()->prune_item_markers AND !in_array( 'core_item_markers', $currentlyPruning ) )
{
Db::i()->delete( 'core_item_markers', array( 'item_member_id IN(?)', Db::i()->select( 'member_id', 'core_members', array( 'last_activity < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_item_markers . 'D' ) )->getTimestamp() ) ) ) );
}
/* Delete old seen IP addresses */
if ( \IPS\Settings::i()->prune_known_ips AND !\in_array( 'core_members_known_ip_addresses', $currentlyPruning ) )
if ( Settings::i()->prune_known_ips AND !in_array( 'core_members_known_ip_addresses', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_members_known_ip_addresses', array( 'last_seen < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_known_ips . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_members_known_ip_addresses', array( 'last_seen < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_known_ips . 'D' ) )->getTimestamp() ) );
}
/* Delete old seen devices */
if ( \IPS\Settings::i()->prune_known_devices AND !\in_array( 'core_members_known_devices', $currentlyPruning ) )
if ( Settings::i()->prune_known_devices AND !in_array( 'core_members_known_devices', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_members_known_devices', array( 'last_seen < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_known_devices . 'D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_members_known_devices', array( 'last_seen < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_known_devices . 'D' ) )->getTimestamp() ) );
}
/* Delete moved links */
if ( \IPS\Settings::i()->topic_redirect_prune )
if ( Settings::i()->topic_redirect_prune )
{
foreach ( \IPS\Content::routedClasses( FALSE, FALSE, TRUE ) as $class )
foreach ( Content::routedClasses( FALSE, FALSE, TRUE ) as $class )
{
if ( isset( $class::$databaseColumnMap['moved_on'] ) )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $class::$databaseTable, array( $class::$databasePrefix . $class::$databaseColumnMap['moved_on'] . '>0 AND ' . $class::$databasePrefix . $class::$databaseColumnMap['moved_on'] . '<?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->topic_redirect_prune . 'D' ) )->getTimestamp() ), $class::$databasePrefix . $class::$databaseColumnId, 100 ), $class ) as $item )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', $class::$databaseTable, array( $class::$databasePrefix . $class::$databaseColumnMap['moved_on'] . '>0 AND ' . $class::$databasePrefix . $class::$databaseColumnMap['moved_on'] . '<?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->topic_redirect_prune . 'D' ) )->getTimestamp() ), $class::$databasePrefix . $class::$databaseColumnId, 100 ), $class ) as $item )
{
$item->delete();
}
@@ -261,78 +275,78 @@ class _cleanup extends \IPS\Task
}
/* Remove warnings points */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members_warn_logs', array( 'wl_expire_date>0 AND wl_expire_date<?', time() ), 'wl_date ASC', 25 ), 'IPS\core\Warnings\Warning' ) as $warning )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'core_members_warn_logs', array( 'wl_expire_date>0 AND wl_expire_date<?', time() ), 'wl_date ASC', 25 ), 'IPS\core\Warnings\Warning' ) as $warning )
{
$member = \IPS\Member::load( $warning->member );
$member = Member::load( $warning->member );
$member->warn_level -= $warning->points;
$member->save();
\IPS\Db::i()->update( 'core_members_warn_logs', array( 'wl_removed_on' => $warning->expire_date ), array( 'wl_id=?', $warning->id ) );
Db::i()->update( 'core_members_warn_logs', array( 'wl_removed_on' => $warning->expire_date ), array( 'wl_id=?', $warning->id ) );
$warning->expire_date = 0;
$warning->save();
}
/* Remove widgets */
if ( \IPS\Application::appIsEnabled('cms') )
if ( Application::appIsEnabled('cms') )
{
\IPS\cms\Widget::emptyTrash();
}
else
{
\IPS\Widget::emptyTrash();
Widget::emptyTrash();
}
/* Reset expired "moderate content till.." timestamps */
\IPS\Db::i()->update( 'core_members', array( 'mod_posts' => 0 ), array( 'mod_posts != -1 and mod_posts <?', time() ) );
Db::i()->update( 'core_members', array( 'mod_posts' => 0 ), array( 'mod_posts != -1 and mod_posts <?', time() ) );
/* Set expired announcements inactive */
\IPS\Db::i()->update( 'core_announcements', array( 'announce_active' => 0 ), array( 'announce_active = 1 and announce_end > 0 and announce_end <?', time() ) );
Db::i()->update( 'core_announcements', array( 'announce_active' => 0 ), array( 'announce_active = 1 and announce_end > 0 and announce_end <?', time() ) );
/* Delete old Google Authenticator code uses */
\IPS\Db::i()->delete( 'core_googleauth_used_codes', array( 'time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1M' ) )->getTimestamp() ) );
Db::i()->delete( 'core_googleauth_used_codes', array( 'time < ?', DateTime::create()->sub( new DateInterval( 'PT1M' ) )->getTimestamp() ) );
/* Close open polls that need closing */
\IPS\Db::i()->update( 'core_polls', array( 'poll_closed' => 1 ), array( 'poll_closed=? AND poll_close_date>? AND poll_close_date<?', 0, -1, time() ) );
Db::i()->update( 'core_polls', array( 'poll_closed' => 1 ), array( 'poll_closed=? AND poll_close_date>? AND poll_close_date<?', 0, -1, time() ) );
/* Delete expired oAuth Authorization Codes */
\IPS\Db::i()->delete( 'core_oauth_server_authorization_codes', array( 'expires<?', time() ) );
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'refresh_token_expires<?', time() ) );
\IPS\Db::i()->delete( 'core_oauth_authorize_prompts', array( 'timestamp<?', ( time() - 300 ) ) );
Db::i()->delete( 'core_oauth_server_authorization_codes', array( 'expires<?', time() ) );
Db::i()->delete( 'core_oauth_server_access_tokens', array( 'refresh_token_expires<?', time() ) );
Db::i()->delete( 'core_oauth_authorize_prompts', array( 'timestamp<?', ( time() - 300 ) ) );
/* Delete any unfinished "Post before register" posts */
foreach ( \IPS\Db::i()->select( '*', 'core_post_before_registering', array( "`member` IS NULL AND followup IS NOT NULL AND followup<" . ( time() - ( 86400 * 6 ) ) ), 'followup ASC' ) as $row )
foreach ( Db::i()->select( '*', 'core_post_before_registering', array( "`member` IS NULL AND followup IS NOT NULL AND followup<" . ( time() - ( 86400 * 6 ) ) ), 'followup ASC' ) as $row )
{
$class = $row['class'];
try
{
$class::load( $row['id'] )->delete();
}
catch ( \OutOfRangeException $e ) { }
catch ( OutOfRangeException $e ) { }
\IPS\Db::i()->delete( 'core_post_before_registering', array( 'class=? AND id=?', $row['class'], $row['id'] ) );
Db::i()->delete( 'core_post_before_registering', array( 'class=? AND id=?', $row['class'], $row['id'] ) );
}
/* Delete old core follow caches */
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'added < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P30D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_follow_count_cache', array( 'added < ?', DateTime::create()->sub( new DateInterval( 'P30D' ) )->getTimestamp() ) );
/* Delete old core statistic caches */
\IPS\Db::i()->delete( 'core_item_statistics_cache', array( 'cache_added < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_item_statistics_cache', array( 'cache_added < ?', DateTime::create()->sub( new DateInterval( 'P1D' ) )->getTimestamp() ) );
/* Delete alerts */
\IPS\Db::i()->delete( 'core_alerts', array( 'alert_end > 0 and alert_end < ?', time() ) );
Db::i()->delete( 'core_alerts', array( 'alert_end > 0 and alert_end < ?', time() ) );
/* Trigger queue item to prune old PMs with no replies in x days */
if( \IPS\Settings::i()->prune_pms )
if( Settings::i()->prune_pms )
{
/* Get count */
$rows = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_message_topics', array( 'mt_last_post_time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_pms . 'D' ) )->getTimestamp() ) ), '\IPS\core\Messenger\Conversation');
$rows = new ActiveRecordIterator( Db::i()->select( '*', 'core_message_topics', array( 'mt_last_post_time < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_pms . 'D' ) )->getTimestamp() ) ), '\IPS\core\Messenger\Conversation');
$count = $rows->count();
if( $count > 5 )
{
/* Queue */
\IPS\Task::queue( 'core', 'PrunePms', array(), 2 );
Task::queue( 'core', 'PrunePms', array(), 2 );
}
else
{
@@ -345,11 +359,8 @@ class _cleanup extends \IPS\Task
}
/* Truncate the output caches table */
\IPS\Output\Cache::i()->deleteExpired( TRUE );
/* Delete Contact Us Verifications older than a month */
\IPS\Db::i()->delete( 'core_contact_verify', array( "verify_time<?", \IPS\DateTime::create()->sub( new \DateInterval( 'P30D' ) )->getTimestamp() ) );
Db::i()->delete( 'core_contact_verify', array( "verify_time<?", DateTime::create()->sub( new DateInterval( 'P30D' ) )->getTimestamp() ) );
return NULL;
}
+17 -10
View File
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\File;
use IPS\Task;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Task that removes attachments that were never claimed
*/
class _cleanupattachments extends \IPS\Task
class cleanupattachments extends Task
{
/**
* Execute
@@ -31,23 +38,23 @@ class _cleanupattachments extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
/* Cleanup - this is deliberately slightly different to the one in \IPS\Text\Parser as it will only delete attachments which have been "saved" (i.e. are not in the middle of being posted) */
foreach ( \IPS\Db::i()->select( '*', 'core_attachments', array( array( 'attach_id NOT IN(?) AND attach_post_key=?', \IPS\Db::i()->select( 'DISTINCT attachment_id', 'core_attachments_map' ), '' ) ) ) as $attachment )
foreach ( Db::i()->select( '*', 'core_attachments', array( array( 'attach_id NOT IN(?) AND attach_post_key=?', Db::i()->select( 'DISTINCT attachment_id', 'core_attachments_map' ), '' ) ) ) as $attachment )
{
try
{
\IPS\Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
\IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
if ( $attachment['attach_thumb_location'] )
{
\IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
}
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
}
return NULL;
+18 -9
View File
@@ -11,16 +11,25 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use Exception;
use IPS\DateTime;
use IPS\Db;
use IPS\File;
use IPS\Task;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Task that removes files from core_files_temp that were never claimed
*/
class _cleanupfiles extends \IPS\Task
class cleanupfiles extends Task
{
/**
* Execute
@@ -31,24 +40,24 @@ class _cleanupfiles extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
foreach ( \IPS\Db::i()->select( '*', 'core_files_temp', array( 'time < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp() ) ) as $file )
foreach ( Db::i()->select( '*', 'core_files_temp', array( 'time < ?', DateTime::create()->sub( new DateInterval( 'P1D' ) )->getTimestamp() ) ) as $file )
{
try
{
\IPS\Db::i()->delete( 'core_files_temp', array( '`id`=?', $file['id'] ) );
Db::i()->delete( 'core_files_temp', array( '`id`=?', $file['id'] ) );
/* storage_extension was added in 4.1.14. If available, remove the file on disk too */
if ( ! empty( $file['storage_extension'] ) )
{
\IPS\File::get( $file['storage_extension'], $file['contents'] )->delete();
File::get( $file['storage_extension'], $file['contents'] )->delete();
}
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
}
return NULL;
+15 -9
View File
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
use const IPS\STORE_METHOD;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* clearcache Task
*/
class _clearcache extends \IPS\Task
class clearcache extends Task
{
/**
* Execute
@@ -31,18 +38,17 @@ class _clearcache extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Note: We previously disabled the task if the caching method was disabled however this lead to people re-enabling through a constants edit which would not re-enabled the task */
\IPS\Db::i()->delete( 'core_cache', array( 'cache_expire<?', time() ) );
\IPS\Output\Cache::i()->deleteExpired();
Db::i()->delete( 'core_cache', array( 'cache_expire<?', time() ) );
/* If we are using Redis, ensure that core_store is empty. We may have switched over to Redis from MySQL and if we switch back, we do not want stale data being used */
if ( \IPS\STORE_METHOD !== 'Database' AND \IPS\Db::i()->select( 'count(*)', 'core_store' )->first() )
if ( STORE_METHOD !== 'Database' AND Db::i()->select( 'count(*)', 'core_store' )->first() )
{
\IPS\Db::i()->delete( 'core_store' );
Db::i()->delete( 'core_store' );
}
return NULL;
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Content\Search\Index;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* clearelasticsearchtasks Task
*/
class _clearelasticsearchtasks extends \IPS\Task
class clearelasticsearchtasks extends Task
{
/**
* Execute
@@ -31,16 +38,17 @@ class _clearelasticsearchtasks extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
if( \IPS\Settings::i()->search_method != 'elastic' )
if( Settings::i()->search_method != 'elastic' )
{
return NULL;
}
\IPS\Content\Search\Index::i()->clearTasks();
Index::i()->clearTasks();
return null;
}
/**
@@ -11,16 +11,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* clearincompletemembers Task
*/
class _clearincompletemembers extends \IPS\Task
class clearincompletemembers extends Task
{
/**
* Execute
@@ -31,14 +41,14 @@ class _clearincompletemembers extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Delete cancelled registration members */
foreach( \IPS\Db::i()->select( 'member_id', 'core_validating', array( 'do_not_delete=0 and reg_cancelled > 0 and reg_cancelled < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) ) as $id )
foreach( Db::i()->select( 'member_id', 'core_validating', array( 'do_not_delete=0 and reg_cancelled > 0 and reg_cancelled < ?', DateTime::create()->sub( new DateInterval( 'PT1H' ) )->getTimestamp() ) ) as $id )
{
$member = \IPS\Member::load( $id );
$member = Member::load( $id );
if( $member->member_id )
{
@@ -46,12 +56,12 @@ class _clearincompletemembers extends \IPS\Task
}
else
{
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=?', $id ) );
Db::i()->delete( 'core_validating', array( 'member_id=?', $id ) );
}
}
/* Delete any incompleted accounts (for example, someone has clicked "Sign in with Twitter" and never provided a username or email */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( array( '(name=? OR email=?)', '', '' ), array( '! (members_bitoptions2 & 16384 ) AND joined<? AND (last_visit=0 OR last_visit IS NULL)', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) ) ), 'IPS\Member' ) as $incompleteMember )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'core_members', array( array( '(name=? OR email=?)', '', '' ), array( '! (members_bitoptions2 & 16384 ) AND joined<? AND (last_visit=0 OR last_visit IS NULL)', DateTime::create()->sub( new DateInterval( 'PT1H' ) )->getTimestamp() ) ) ), 'IPS\Member' ) as $incompleteMember )
{
$incompleteMember->delete();
}
+16 -8
View File
@@ -11,16 +11,24 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Session;
use IPS\Session\Store;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* clearsessions Task
*/
class _clearsessions extends \IPS\Task
class clearsessions extends Task
{
/**
* Execute
@@ -31,14 +39,14 @@ class _clearsessions extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$timeout = \IPS\Session::sessionLifetime();
$timeout = Session::sessionLifetime();
\IPS\Db::i()->delete( 'core_sys_cp_sessions', array( 'session_running_time<?', ( time() - $timeout ) ) );
$class = \IPS\Session\Store::i();
Db::i()->delete( 'core_sys_cp_sessions', array( 'session_running_time<?', ( time() - $timeout ) ) );
$class = Store::i();
$class::clearSessions( $timeout );
return NULL;
@@ -1,26 +1,32 @@
<?php
/**
* @brief Promote Task
* @brief cleartagpins Task
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 28 Feb 2017
{subpackage}
* @since 13 May 2024
*/
namespace IPS\core\tasks;
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception as TaskException;
use function defined;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Promote Task
* cleartagpins Task
*/
class _promote extends \IPS\Task
class cleartagpins extends Task
{
/**
* Execute
@@ -31,12 +37,11 @@ class _promote extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws TaskException
*/
public function execute()
public function execute() : mixed
{
\IPS\core\Promote::processQueue();
Db::i()->delete( 'core_tags_pinned', [ 'pinned_end_date > ? and pinned_end_date < ?', 0, time() ] );
return NULL;
}
@@ -49,7 +54,7 @@ class _promote extends \IPS\Task
*
* @return void
*/
public function cleanup()
public function cleanup() : void
{
}
+22 -11
View File
@@ -11,16 +11,25 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
use IPS\Task;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* clubrebuild Task
*/
class _clubrebuild extends \IPS\Task
class clubrebuild extends Task
{
/**
* Execute
@@ -31,26 +40,26 @@ class _clubrebuild extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
if ( !\IPS\Settings::i()->clubs )
if ( !Settings::i()->clubs )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'clubrebuild' ) );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'clubrebuild' ) );
return NULL;
}
$this->runUntilTimeout( function()
{
$select = \IPS\Db::i()->select( '*', 'core_clubs', array( 'rebuilt is null or rebuilt<?', time() - 1200 ), 'rebuilt ASC', 10 );
$select = Db::i()->select( '*', 'core_clubs', array( 'rebuilt is null or rebuilt<?', time() - 1200 ), 'rebuilt ASC', 10 );
if ( !$select->count() )
{
return FALSE;
}
foreach ( new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\Member\Club' ) as $club )
foreach ( new ActiveRecordIterator( $select, 'IPS\Member\Club' ) as $club )
{
$club->content = 0;
$club->last_activity = 0;
@@ -62,14 +71,14 @@ class _clubrebuild extends \IPS\Task
$nodeClass = $node['node_class'];
$node = $nodeClass::load( $node['node_id'] );
if ( $lastCommentTime = $node->getLastCommentTime( new \IPS\Member ) and $lastCommentTime->getTimestamp() > $club->last_activity )
if ( $lastCommentTime = $node->getLastCommentTime( new Member ) and $lastCommentTime->getTimestamp() > $club->last_activity )
{
$club->last_activity = $lastCommentTime->getTimestamp();
}
$club->content += (int) $node->getContentItemCount();
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
}
$club->rebuilt = time();
@@ -78,6 +87,8 @@ class _clubrebuild extends \IPS\Task
return TRUE;
} );
return null;
}
/**
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\core\Stream\Subscription;
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* dailyStreamSubscriptions Task
*/
class _dailyStreamSubscriptions extends \IPS\Task
class dailyStreamSubscriptions extends Task
{
/**
* Execute
@@ -31,12 +38,12 @@ class _dailyStreamSubscriptions extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Disable task if no subscriptions */
$select = \IPS\Db::i()->select( '*', 'core_stream_subscriptions', array( 'frequency=?', 'daily' ));
$select = Db::i()->select( '*', 'core_stream_subscriptions', array( 'frequency=?', 'daily' ));
if( !$select->count() )
{
$this->enabled = FALSE;
@@ -47,7 +54,7 @@ class _dailyStreamSubscriptions extends \IPS\Task
$this->runUntilTimeout( function()
{
return \IPS\core\Stream\Subscription::sendBatch( 'daily' );
return Subscription::sendBatch( 'daily' );
});
return NULL;
}
+21 -10
View File
@@ -11,16 +11,27 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use OutOfRangeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* deletecontent Task
*/
class _deletecontent extends \IPS\Task
class deletecontent extends Task
{
/**
* Execute
@@ -31,16 +42,16 @@ class _deletecontent extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout( function()
{
$timeago = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->dellog_retention_period . 'D' ) );
$timeago = DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->dellog_retention_period . 'D' ) );
$count = 0;
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_deletion_log', array( "dellog_deleted_date<?", $timeago->getTimestamp() ), 'dellog_deleted_date ASC', array( 0, 20 ) ), 'IPS\core\DeletionLog' ) AS $log )
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'core_deletion_log', array( "dellog_deleted_date<?", $timeago->getTimestamp() ), 'dellog_deleted_date ASC', array( 0, 20 ) ), 'IPS\core\DeletionLog' ) AS $log )
{
try
{
@@ -52,20 +63,20 @@ class _deletecontent extends \IPS\Task
/* Make sure that the content is flagged for deletion */
if( $content->hidden() !== -2 )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
$content->delete();
}
}
/* If the content is gone already, don't let an uncaught exception bubble up...just remove the deletion log orphaned entry */
catch( \OutOfRangeException $e ){}
catch( OutOfRangeException $e ){}
$log->delete();
$count++;
}
return $count ? TRUE : FALSE;
return (bool) $count;
} );
return NULL;
+12 -6
View File
@@ -11,16 +11,22 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\core\Digest\Digest as DigestClass;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* digest Task
*/
class _digest extends \IPS\Task
class digest extends Task
{
/**
* Execute
@@ -31,13 +37,13 @@ class _digest extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout( function()
{
return \IPS\core\Digest\Digest::sendDigestBatch( 'daily' );
return DigestClass::sendDigestBatch( 'daily' );
});
return NULL;
+30 -18
View File
@@ -11,16 +11,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use DateTimeZone;
use IPS\DateTime;
use IPS\Db;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* leaderboard Task
*/
class _leaderboard extends \IPS\Task
class leaderboard extends Task
{
/**
* Execute
@@ -31,39 +41,39 @@ class _leaderboard extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Get the most recent update */
$date = \IPS\Db::i()->select( 'MAX(leader_date)', 'core_reputation_leaderboard_history' )->first();
$timezone = new \DateTimeZone( \IPS\Settings::i()->reputation_timezone );
$date = Db::i()->select( 'MAX(leader_date)', 'core_reputation_leaderboard_history' )->first();
$timezone = new DateTimeZone( Settings::i()->reputation_timezone );
if ( $date )
{
/* Only go back 10 days max */
if ( $date < ( time() - 864000 ) )
{
$startDate = \IPS\DateTime::ts( time(), true )->setTimezone( $timezone )->sub( new \DateInterval('P10D') )->setTime( 0, 0, 1 );
$startDate = DateTime::ts( time(), true )->setTimezone( $timezone )->sub( new DateInterval('P10D') )->setTime( 0, 0, 1 );
}
else
{
$startDate = \IPS\DateTime::ts( $date, true )->setTimezone( $timezone )->setTime( 0, 0, 1 );
$startDate = DateTime::ts( $date, true )->setTimezone( $timezone )->setTime( 0, 0, 1 );
}
}
else
{
$startDate = new \IPS\DateTime( 'yesterday midnight', $timezone );
$startDate = new DateTime( 'yesterday midnight', $timezone );
/* Do we need to run this task at all? If we don't have any records in core_reputation_index we can skip this task */
$existing = \IPS\Db::i()->select( 'count(*)', 'core_reputation_index' )->first();
$existing = Db::i()->select( 'count(*)', 'core_reputation_index' )->first();
if ( !$existing )
{
return NULL;
}
}
$yesterdayEnd = new \IPS\DateTime( 'today midnight', $timezone );
$yesterdayEnd = new DateTime( 'today midnight', $timezone );
$diff = $startDate->diff( $yesterdayEnd );
$difference = $diff->days > 0 ? $diff->days + 1 : 1;
@@ -75,20 +85,20 @@ class _leaderboard extends \IPS\Task
/* As this can run multiple times, and the unique constraint is member_id, position, it is possible to end up with multiple members with the same positon */
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
\IPS\Db::i()->delete( 'core_reputation_leaderboard_history', array( 'leader_date BETWEEN ? and ?', $date - 4, $date ) );
Db::i()->delete( 'core_reputation_leaderboard_history', array( 'leader_date BETWEEN ? and ?', $date - 4, $date ) );
$where = array();
$where[] = array( 'member_received > 0 AND rep_date BETWEEN ? and ?', $startDate->setTime( 0, 0, 1 )->getTimeStamp(), $startDate->setTime( 23, 59, 59 )->getTimeStamp() );
$where[] = \IPS\Db::i()->in( 'member_group_id', explode( ',', \IPS\Settings::i()->leaderboard_excluded_groups ), TRUE );
$where[] = Db::i()->in( 'member_group_id', explode( ',', Settings::i()->leaderboard_excluded_groups ), TRUE );
foreach( \IPS\Db::i()->select( 'core_reputation_index.member_received as themember, SUM(rep_rating) as rep', 'core_reputation_index', $where, 'rep DESC, themember ASC', 4, 'themember' )->join( 'core_members', 'core_members.member_id=core_reputation_index.member_received' )->setKeyField('themember')->setValueField('rep') as $member => $rep )
foreach( Db::i()->select( 'core_reputation_index.member_received as themember, SUM(rep_rating) as rep', 'core_reputation_index', $where, 'rep DESC, themember ASC', 4, 'themember' )->join( 'core_members', 'core_members.member_id=core_reputation_index.member_received' )->setKeyField('themember')->setValueField('rep') as $member => $rep )
{
if ( $member and $rep )
{
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
$position++;
\IPS\Db::i()->replace( 'core_reputation_leaderboard_history', array(
Db::i()->replace( 'core_reputation_leaderboard_history', array(
'leader_date' => $date,
'leader_member_id' => $member,
'leader_position' => $position,
@@ -110,7 +120,7 @@ class _leaderboard extends \IPS\Task
{
$position++;
\IPS\Db::i()->replace( 'core_reputation_leaderboard_history', array(
Db::i()->replace( 'core_reputation_leaderboard_history', array(
'leader_date' => $date - $position,
'leader_member_id' => 0,
'leader_position' => $position,
@@ -119,8 +129,10 @@ class _leaderboard extends \IPS\Task
}
}
$startDate = $startDate->add( new \DateInterval('P1D') )->setTime( 0, 0, 1 );
$startDate = $startDate->add( new DateInterval('P1D') )->setTime( 0, 0, 1 );
}
return null;
}
/**
+18 -11
View File
@@ -5,28 +5,35 @@
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 13 Sep 2024
* @since 02 Oct 2024
*/
namespace IPS\core\tasks;
use BadMethodCallException;
use Exception;
use IPS\Task;
use IPS\Task\Exception as TaskException;
use IPS\Data\Store;
use IPS\Node\Model;
use IPS\Redis;
use OutOfRangeException;
use RedisException;
use function array_key_exists;
use function is_array;
use function defined;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* nodeRecounts Task
*/
class _nodeRecounts extends \IPS\Task
class nodeRecounts extends Task
{
/**
* Execute
@@ -37,28 +44,28 @@ class _nodeRecounts extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws TaskException
*/
public function execute(): mixed
public function execute() : mixed
{
$allKeys = [];
try
{
if( ! Redis::isEnabled() )
{
throw new \BadMethodCallException;
throw new BadMethodCallException;
}
$allKeys = Redis::i()->hGetAll('nodeSyncTimes');
}
catch( \BadMethodCallException | \RedisException )
catch( BadMethodCallException | RedisException )
{
try
{
$key = 'nodeSyncTimes';
$allKeys = Store::i()->$key;
}
catch( \OutOfRangeException ){}
catch( OutOfRangeException ){}
}
if ( ! is_array( $allKeys ) or ! count( $allKeys ))
@@ -85,7 +92,7 @@ class _nodeRecounts extends \IPS\Task
/* Recount items, comments, reviews and the last comment data */
$node->runScheduledRebuild();
}
catch( \Exception $e )
catch( Exception $e )
{
continue;
}
@@ -106,7 +113,7 @@ class _nodeRecounts extends \IPS\Task
*
* @return void
*/
public function cleanup()
public function cleanup() : void
{
}
+18 -10
View File
@@ -11,16 +11,24 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Session\Store;
use IPS\Task;
use IPS\Task\Exception;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* onlineusers Task
*/
class _onlineusers extends \IPS\Task
class onlineusers extends Task
{
/**
* Execute
@@ -31,9 +39,9 @@ class _onlineusers extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* We want the rows to have the same timestamp exactly */
$time = time();
@@ -43,19 +51,19 @@ class _onlineusers extends \IPS\Task
try
{
$onlineGuests = \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_GUESTS | \IPS\Session\Store::ONLINE_COUNT_ONLY, 'desc', NULL, NULL, TRUE );
$onlineMembers = \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_MEMBERS | \IPS\Session\Store::ONLINE_COUNT_ONLY, 'desc', NULL, NULL, TRUE );
$onlineGuests = Store::i()->getOnlineUsers( Store::ONLINE_GUESTS | Store::ONLINE_COUNT_ONLY, 'desc', NULL, NULL, TRUE );
$onlineMembers = Store::i()->getOnlineUsers( Store::ONLINE_MEMBERS | Store::ONLINE_COUNT_ONLY, 'desc', NULL, NULL, TRUE );
}
catch( \UnderflowException $e) {}
catch( UnderflowException $e) {}
\IPS\Db::i()->insert( 'core_statistics', array(
Db::i()->insert( 'core_statistics', array(
'type' => 'online_users',
'time' => $time,
'value_4' => 'guests',
'value_1' => $onlineGuests
) );
\IPS\Db::i()->insert( 'core_statistics', array(
Db::i()->insert( 'core_statistics', array(
'type' => 'online_users',
'time' => $time,
'value_4' => 'members',
-93
View File
@@ -1,93 +0,0 @@
<?php
/**
* @brief POP3 Task
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 16 Apr 2014
*/
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* POP3 Task
*/
class _pop extends \IPS\Task
{
/**
* Execute
*
* If ran successfully, should return anything worth logging. Only log something
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
*/
public function execute()
{
/* If we haven't set up POP3, disable ourselves */
if ( !\IPS\Settings::i()->pop3_server )
{
$this->enabled = FALSE;
$this->save();
return;
}
/* Do it */
try
{
/* Connect */
$pop3 = new \IPS\Email\Incoming\PopImap( \IPS\Settings::i()->pop3_server, \IPS\Settings::i()->pop3_tls, \IPS\Settings::i()->pop3_port, \IPS\Settings::i()->pop3_user, \IPS\Settings::i()->pop3_password );
/* Fetch emails */
if ( $emailsInInbox = $pop3->emailsInInbox() )
{
foreach ( range( 1, min( $emailsInInbox, 50 ) ) as $i )
{
try
{
$incomingEmail = new \IPS\Email\Incoming\Email( $pop3->getEmail( $i ) );
$incomingEmail->route();
$pop3->deleteEmail( $i );
}
catch ( \IPS\Email\Incoming\PopImapException $e )
{
\IPS\Log::log( $e, 'pop3' );
}
}
}
/* Disconnect */
unset( $pop3 );
}
catch ( \Exception $exception )
{
\IPS\Log::log( $exception, 'pop3' );
throw new \IPS\Task\Exception( $this, $exception->getMessage() );
}
}
/**
* Cleanup
*
* If your task takes longer than 15 minutes to run, this method
* will be called before execute(). Use it to clean up anything which
* may not have been done
*
* @return void
*/
public function cleanup()
{
}
}
@@ -11,16 +11,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Email;
use IPS\Lang;
use IPS\Task;
use OutOfRangeException;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* postBeforeRegisterFollowup Task
*/
class _postBeforeRegisterFollowup extends \IPS\Task
class postBeforeRegisterFollowup extends Task
{
/**
* Execute
@@ -31,21 +41,21 @@ class _postBeforeRegisterFollowup extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout( function()
{
/* Get the email */
try
{
$userData = \IPS\Db::i()->select( array( 'email', 'language', 'secret' ), 'core_post_before_registering', array( "`member` IS NULL and followup IS NULL and timestamp<" . ( time() - ( 86400 * 2 ) ) ), 'timestamp ASC', 1 )->first();
$userData = Db::i()->select( array( 'email', 'language', 'secret' ), 'core_post_before_registering', array( "`member` IS NULL and followup IS NULL and timestamp<" . ( time() - ( 86400 * 2 ) ) ), 'timestamp ASC', 1 )->first();
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
/* Disable the task if there is nothing at all left to process */
if( \IPS\Db::i()->select( 'COUNT(*)', 'core_post_before_registering', array( "`member` IS NULL") )->first() === 0 )
if( Db::i()->select( 'COUNT(*)', 'core_post_before_registering', array( "`member` IS NULL") )->first() === 0 )
{
$this->enabled = FALSE;
$this->save();
@@ -56,7 +66,7 @@ class _postBeforeRegisterFollowup extends \IPS\Task
/* Get the associated content */
$content = array();
foreach ( \IPS\Db::i()->select( array( 'class', 'id' ), 'core_post_before_registering', array( 'email=?', $userData['email'] ) ) as $contentRow )
foreach ( Db::i()->select( array( 'class', 'id' ), 'core_post_before_registering', array( 'email=?', $userData['email'] ) ) as $contentRow )
{
$class = $contentRow['class'];
try
@@ -64,14 +74,14 @@ class _postBeforeRegisterFollowup extends \IPS\Task
/* Remove any data if the content class doesn't exist any more */
if ( !class_exists( $class ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
$content[] = $class::load( $contentRow['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
\IPS\Db::i()->delete( 'core_post_before_registering', array( 'class=? AND id=?', $contentRow['class'], $contentRow['id'] ) );
Db::i()->delete( 'core_post_before_registering', array( 'class=? AND id=?', $contentRow['class'], $contentRow['id'] ) );
}
}
if ( !$content )
@@ -82,23 +92,25 @@ class _postBeforeRegisterFollowup extends \IPS\Task
/* Build the email */
try
{
$language = \IPS\Lang::load( $userData['language'] );
$language = Lang::load( $userData['language'] );
}
catch ( \Exception $e )
catch ( Exception $e )
{
$language = \IPS\Lang::load( \IPS\Lang::defaultLanguage() );
$language = Lang::load( Lang::defaultLanguage() );
}
$email = \IPS\Email::buildFromTemplate( 'core', 'postBeforeRegisterFollowup', array( $content, $userData['secret'] ), \IPS\Email::TYPE_BULK );
$email = Email::buildFromTemplate( 'core', 'postBeforeRegisterFollowup', array( $content, $userData['secret'] ), Email::TYPE_BULK );
$email->language = $language;
$email->setUnsubscribe( 'core', 'unsubscribeNotNeeded' );
$email->send( $userData['email'] );
/* Update the row */
\IPS\Db::i()->update( 'core_post_before_registering', array( 'followup' => time() ), array( 'email=?', $userData['email'] ) );
Db::i()->update( 'core_post_before_registering', array( 'followup' => time() ), array( 'email=?', $userData['email'] ) );
/* Return */
return TRUE;
} );
return null;
}
/**
+26 -15
View File
@@ -11,23 +11,34 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Login;
use IPS\Member;
use IPS\Task;
use UnderflowException;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Profile-sync Task
*/
class _profilesync extends \IPS\Task
class profilesync extends Task
{
/**
* Execute
*
* @return void
* @return mixed
*/
public function execute()
public function execute() : mixed
{
/* Do we have any login methods that even support syncing enabled? */
if( !$this->canSync() )
@@ -38,7 +49,7 @@ class _profilesync extends \IPS\Task
$where = array( array( "temp_ban=?", 0 ), array( "profilesync_lastsync > ?", 0 ) );
/* Only check accounts that have visited in the last 6 months */
$where[] = array( "GREATEST(last_activity, last_visit) > ?", \IPS\DateTime::create()->sub( new \DateInterval('P6M') )->getTimestamp() );
$where[] = array( "GREATEST(last_activity, last_visit) > ?", DateTime::create()->sub( new DateInterval('P6M') )->getTimestamp() );
/* And only check accounts that are actually synchronizing, UNLESS the admin is also forcing synchronization for any login methods */
if( !$this->hasForcedSync() )
@@ -47,7 +58,7 @@ class _profilesync extends \IPS\Task
}
$totalToSync = \IPS\Db::i()->select( 'count(*)', 'core_members', $where )->first();
$totalToSync = Db::i()->select( 'count(*)', 'core_members', $where )->first();
if( !$totalToSync )
{
@@ -67,14 +78,14 @@ class _profilesync extends \IPS\Task
{
try
{
$member = \IPS\Db::i()->select( '*', 'core_members', $where, 'profilesync_lastsync ASC', 1 )->first();
$member = Db::i()->select( '*', 'core_members', $where, 'profilesync_lastsync ASC', 1 )->first();
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
return FALSE;
}
$member = \IPS\Member::constructFromData( $member );
$member = Member::constructFromData( $member );
$member->profileSync();
return TRUE;
@@ -88,9 +99,9 @@ class _profilesync extends \IPS\Task
*
* @return bool
*/
protected function canSync()
protected function canSync() : bool
{
foreach ( \IPS\Login::methods() as $method )
foreach ( Login::methods() as $method )
{
if( $method->hasSyncOptions() )
{
@@ -106,11 +117,11 @@ class _profilesync extends \IPS\Task
*
* @return bool
*/
protected function hasForcedSync()
protected function hasForcedSync() : bool
{
foreach ( \IPS\Login::methods() as $method )
foreach ( Login::methods() as $method )
{
if( \count( $method->forceSync() ) )
if( count( $method->forceSync() ) )
{
return TRUE;
}
+17 -9
View File
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Member;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* pruneipaddresses Task
*/
class _pruneipaddresses extends \IPS\Task
class pruneipaddresses extends Task
{
/**
* Execute
@@ -31,17 +38,18 @@ class _pruneipaddresses extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
if ( \IPS\Settings::i()->ip_address_prune < 1 )
if ( Settings::i()->ip_address_prune < 1 )
{
return NULL;
}
$time = time() - ( 86400 * \IPS\Settings::i()->ip_address_prune );
\IPS\Member::pruneAllLoggedIpAddresses( $time );
$time = time() - ( 86400 * Settings::i()->ip_address_prune );
Member::pruneAllLoggedIpAddresses( $time );
return NULL;
}
+18 -8
View File
@@ -11,16 +11,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\Content\Search\Index;
use IPS\DateTime;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use UnexpectedValueException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* prunesearchindex Task
*/
class _prunesearchindex extends \IPS\Task
class prunesearchindex extends Task
{
/**
* Execute
@@ -31,18 +41,18 @@ class _prunesearchindex extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Prune search index */
if ( \IPS\Settings::i()->search_method == 'mysql' and \IPS\Settings::i()->search_index_timeframe )
if ( Settings::i()->search_method == 'mysql' and Settings::i()->search_index_timeframe )
{
try
{
\IPS\Content\Search\Index::i()->prune( \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->search_index_timeframe . 'D' ) ) );
Index::i()->prune( DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->search_index_timeframe . 'D' ) ) );
}
catch ( \UnexpectedValueException $e ) { }
catch ( UnexpectedValueException $e ) { }
}
return NULL;
+14 -7
View File
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Log;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* prunesystemlogs Task
*/
class _prunesystemlogs extends \IPS\Task
class prunesystemlogs extends Task
{
/**
* Execute
@@ -31,13 +38,13 @@ class _prunesystemlogs extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
if( \IPS\Settings::i()->prune_log_system )
if( Settings::i()->prune_log_system )
{
\IPS\Log::pruneLogs( \IPS\Settings::i()->prune_log_system );
Log::pruneLogs( Settings::i()->prune_log_system );
}
return NULL;
+22 -10
View File
@@ -11,16 +11,25 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Content;
use IPS\Db;
use IPS\IPS;
use IPS\Task;
use IPS\Task\Exception;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ($_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0') . ' 403 Forbidden' );
exit;
}
/**
* publish Task
*/
class _publish extends \IPS\Task
class publish extends Task
{
/**
* Execute
@@ -30,32 +39,35 @@ class _publish extends \IPS\Task
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @return string|null Message to log or NULL
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$types = array();
foreach ( \IPS\Content::routedClasses( FALSE, FALSE, TRUE ) as $class )
foreach ( Content::routedClasses( FALSE, FALSE, TRUE ) as $class )
{
if( is_subclass_of( $class, 'IPS\Content\FuturePublishing' ) )
if( IPS::classUsesTrait( $class, 'IPS\Content\FuturePublishing' ) )
{
$types[] = $class;
}
}
if( \count( $types ) )
if( count( $types ) )
{
foreach( $types as $class )
{
foreach( \IPS\Db::i()->select( '*', $class::$databaseTable, array( $class::$databasePrefix . $class::$databaseColumnMap['is_future_entry'] . '=1 and ' . $class::$databasePrefix . $class::$databaseColumnMap['date'] . ' <= ' . time() ) ) as $row )
/* @var $databaseColumnMap array */
foreach( Db::i()->select( '*', $class::$databaseTable, array( $class::$databasePrefix . $class::$databaseColumnMap['is_future_entry'] . '=1 and ' . $class::$databasePrefix . $class::$databaseColumnMap['date'] . ' <= ' . time() ) ) as $row )
{
$obj = $class::constructFromData( $row );
$obj->publish();
}
}
}
return NULL;
}
/**
+15 -7
View File
@@ -11,16 +11,24 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* pwaprune Task
*/
class _pwaprune extends \IPS\Task
class pwaprune extends Task
{
/**
* Execute
@@ -31,13 +39,13 @@ class _pwaprune extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$expiration = \IPS\DateTime::ts( time() )->sub( new \DateInterval( 'P2D' ) )->getTimestamp();
$expiration = DateTime::ts( time() )->sub( new DateInterval( 'P2D' ) )->getTimestamp();
\IPS\Db::i()->delete( 'core_notifications_pwa_queue', array( 'expiration<?', $expiration ) );
Db::i()->delete( 'core_notifications_pwa_queue', array( 'expiration<?', $expiration ) );
return NULL;
}
+15 -7
View File
@@ -11,16 +11,22 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Task;
use IPS\Task\Exception;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Queue Task
*/
class _queue extends \IPS\Task
class queue extends Task
{
/**
* Execute
@@ -31,28 +37,30 @@ class _queue extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout( function(){
/* Try and get a queue item */
try
{
/* Run the next queue task, if any */
\IPS\Task::runQueue();
Task::runQueue();
/* Continue */
return TRUE;
}
/* If there's no queue items left, disable this task and return */
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
$this->enabled = FALSE;
$this->save();
return FALSE;
}
});
return null;
}
/**
+25 -13
View File
@@ -12,16 +12,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\core\Rss\Import;
use IPS\DateTime;
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* rssimport Task
*/
class _rssimport extends \IPS\Task
class rssimport extends Task
{
/**
* Execute
@@ -32,27 +42,27 @@ class _rssimport extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
* @throws \Exception
*/
public function execute()
public function execute() : mixed
{
$timeCheck = new \IPS\DateTime;
$timeCheck->sub( new \DateInterval( 'PT10M' ) );
$timeCheck = new DateTime;
$timeCheck->sub( new DateInterval( 'PT10M' ) );
$this->runUntilTimeout(function() use ( $timeCheck ) {
try
{
$feed = \IPS\core\Rss\Import::constructFromData( \IPS\Db::i()->select( '*', 'core_rss_import', array( 'rss_import_enabled=1 AND rss_import_last_import<?', $timeCheck->getTimestamp() ), 'rss_import_last_import ASC', 1 )->first() );
$feed = Import::constructFromData( Db::i()->select( '*', 'core_rss_import', array( 'rss_import_enabled=1 AND rss_import_last_import<?', $timeCheck->getTimestamp() ), 'rss_import_last_import ASC', 1 )->first() );
$feed->run();
}
/* There's nothing more left to process */
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
/* Check to see if there are any feeds.. If no feed, we can disable the task */
if( !\IPS\Db::i()->select( 'count(rss_import_id)', 'core_rss_import', array( 'rss_import_enabled=1' ), NULL, 1 )->first() )
if( !Db::i()->select( 'count(rss_import_id)', 'core_rss_import', array( 'rss_import_enabled=1' ), NULL, 1 )->first() )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'rssimport' ) );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'rssimport' ) );
}
/* No further processing needed */
@@ -62,17 +72,19 @@ class _rssimport extends \IPS\Task
catch ( \Exception $e )
{
/* If there is an error, we need to log it but the error should not prevent other feeds from importing */
if ( isset( $feed ) AND ( $feed instanceof \IPS\core\Rss\Import ) )
if ( isset( $feed ) AND ( $feed instanceof Import ) )
{
$feed->last_import = time();
$feed->save();
}
throw new \IPS\Task\Exception( $this, $e->getMessage() );
throw new Exception( $this, $e->getMessage() );
}
/* Run again to see if there's anything left */
return TRUE;
});
return null;
}
/**
+30 -20
View File
@@ -11,16 +11,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\File;
use IPS\File\Amazon;
use IPS\Task;
use IPS\Task\Exception;
use UnderflowException;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* s3Delete Task
* s3_delete Task
*/
class _s3Delete extends \IPS\Task
class s3Delete extends Task
{
/**
* Execute
@@ -31,30 +41,30 @@ class _s3Delete extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
try
{
$s3 = \IPS\Db::i()->select( '*', 'core_s3_deletions' )->first();
$s3 = Db::i()->select( '*', 'core_s3_deletions' )->first();
$obj = \IPS\File::getClass('core_Theme');
$obj = File::getClass('core_Theme');
if ( !( $obj instanceof \IPS\File\Amazon ) )
if ( !( $obj instanceof Amazon ) )
{
/* Class is not Amazon, so just stop here and truncate the table as there's nothing we can really do now. */
\IPS\Db::i()->delete( 'core_s3_deletions' );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 's3Delete' ) );
Db::i()->delete( 'core_s3_deletions' );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 's3Delete' ) );
return NULL;
}
$keys = $obj->getContainerKeys( $s3['s3_container'], 101, '', $s3['s3_marker'] );
$keys = $obj->getContainerKeys( $s3['s3_container'], 101, '', ( $s3['s3_marker'] ?? '' ) );
if ( \count( $keys ) )
if ( count( $keys ) )
{
/* Get the 51st key, which will be the marker for the next iteration if we have 51 keys, otherwise, make marker null so it's removed in the next iteration */
if ( \count( $keys ) < 101 )
if ( count( $keys ) < 101 )
{
$marker = NULL;
}
@@ -70,31 +80,31 @@ class _s3Delete extends \IPS\Task
{
if ( $time <= $s3['s3_added'] )
{
\IPS\File::getClass('core_Theme')->deleteByKey( $key );
File::getClass('core_Theme')->deleteByKey( $key );
}
}
if ( $marker )
{
/* Update the marker, there may be more to go */
\IPS\Db::i()->update( 'core_s3_deletions', array( 's3_marker' => $marker ), array( 's3_container=?', $s3['s3_container'] ) );
Db::i()->update( 'core_s3_deletions', array( 's3_marker' => $marker ), array( 's3_container=?', $s3['s3_container'] ) );
}
else
{
/* Last batch, possible some keys not deleted if time didn't match */
\IPS\Db::i()->delete( 'core_s3_deletions', array( 's3_container=?', $s3['s3_container'] ) );
Db::i()->delete( 'core_s3_deletions', array( 's3_container=?', $s3['s3_container'] ) );
}
}
else
{
/* If no keys, delete container row from s3_deletions */
\IPS\Db::i()->delete( 'core_s3_deletions', array( 's3_container=?', $s3['s3_container'] ) );
Db::i()->delete( 'core_s3_deletions', array( 's3_container=?', $s3['s3_container'] ) );
}
}
catch( \UnderflowException $ex )
catch( UnderflowException $ex )
{
/* Nothing to do, so switch off the task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 's3Delete' ) );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 's3Delete' ) );
}
return NULL;
+17 -9
View File
@@ -11,25 +11,33 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Log;
use IPS\Sitemap;
use IPS\Task;
use function count;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Task to generate sitemaps
*/
class _sitemapgenerator extends \IPS\Task
class sitemapgenerator extends Task
{
/**
* Execute
*
* @return void
* @return mixed
*/
public function execute()
public function execute() : mixed
{
$generator = new \IPS\Sitemap;
$generator = new Sitemap;
$this->runUntilTimeout( function() use( $generator )
{
@@ -38,15 +46,15 @@ class _sitemapgenerator extends \IPS\Task
/* If it returns false, we're done for now */
return $generator->buildNextSitemap();
}
catch( \Exception $e )
catch( Exception $e )
{
\IPS\Log::log( $e, 'sitemap_generator' );
Log::log( $e, 'sitemap_generator' );
$generator->log[] = $e->getMessage();
return FALSE;
}
} );
if( \count( $generator->log ) )
if( count( $generator->log ) )
{
return $generator->log;
}
+28 -10
View File
@@ -11,16 +11,27 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
use function is_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Unlock Members Task
*/
class _unlockmembers extends \IPS\Task
class unlockmembers extends Task
{
/**
* Execute
@@ -30,22 +41,29 @@ class _unlockmembers extends \IPS\Task
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @return mixed Message to log or NULL
* @throws Exception|\Exception
*/
public function execute()
public function execute() : mixed
{
if( !\IPS\Settings::i()->ipb_bruteforce_unlock or !\IPS\Settings::i()->ipb_bruteforce_period or !\IPS\Settings::i()->ipb_bruteforce_attempts )
if( !Settings::i()->ipb_bruteforce_unlock or !Settings::i()->ipb_bruteforce_period or !Settings::i()->ipb_bruteforce_attempts )
{
return NULL;
}
/* Clear out old data */
\IPS\Db::i()->delete( 'core_login_failures', [ 'login_date<? AND login_ip_address IS NOT NULL AND login_member_id IS NOT NULL', ( new \IPS\DateTime() )->sub( new \DateInterval( 'PT' . \IPS\Settings::i()->ipb_bruteforce_period . 'M' ) )->getTimestamp() ] );
Db::i()->delete( 'core_login_failures', [ 'login_date<? AND login_ip_address IS NOT NULL AND login_member_id IS NOT NULL', ( new DateTime() )->sub( new DateInterval( 'PT' . Settings::i()->ipb_bruteforce_period . 'M' ) )->getTimestamp() ] );
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( 'failed_login_count >= ?', \IPS\Settings::i()->ipb_bruteforce_attempts ) ), 'IPS\Member') AS $member )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'core_members', array( 'failed_login_count >= ?', Settings::i()->ipb_bruteforce_attempts ) ), 'IPS\Member') AS $member )
{
$member->recountFailedLogins();
$where = [
'login_date>=? AND login_ip_address IS NOT NULL AND login_member_id=?',
( new DateTime )->sub( new DateInterval( 'PT' . Settings::i()->ipb_bruteforce_period . 'M' ) )->getTimestamp(),
$this->member_id
];
$member->failed_login_count = max( iterator_to_array( Db::i()->select( 'count(login_ip_address)', 'core_login_failures', $where, NULL, NULL, 'login_ip_address' ) ) );
$member->save();
}
return NULL;
+64 -52
View File
@@ -11,37 +11,58 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Application;
use IPS\core\AdminNotification;
use IPS\Data\Store;
use IPS\Db;
use IPS\Http\Url;
use IPS\IPS;
use IPS\Lang;
use IPS\Log;
use IPS\Settings;
use IPS\Task;
use RuntimeException;
use Throwable;
use UnderflowException;
use UnexpectedValueException;
use function count;
use function defined;
use const IPS\IPS_ALPHA_BUILD;
use const IPS\USE_DEVELOPMENT_BUILDS;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* updatecheck Task
*/
class _updatecheck extends \IPS\Task
class updatecheck extends Task
{
/**
* @brief Type to send to update server
*/
public $type = 'task';
public string $type = 'task';
/**
* Execute
*
* @return mixed Message to log or NULL
*/
public function execute()
public function execute() : mixed
{
/* Refresh stored license data */
\IPS\IPS::licenseKey( TRUE );
IPS::licenseKey( TRUE );
$fails = array();
/* Do IPS apps */
$versions = array();
foreach ( \IPS\Db::i()->select( '*', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\IPS::$ipsApps ) ) as $app )
foreach ( Db::i()->select( '*', 'core_applications', Db::i()->in( 'app_directory', IPS::$ipsApps ) ) as $app )
{
if ( $app['app_enabled'] )
{
@@ -49,12 +70,12 @@ class _updatecheck extends \IPS\Task
}
}
$version = min( $versions );
$url = \IPS\Http\Url::ips('updateCheck')->setQueryString( array( 'type' => $this->type, 'key' => \IPS\Settings::i()->ipb_reg_number ) );
if ( \IPS\USE_DEVELOPMENT_BUILDS )
$url = Url::ips('updateCheck5')->setQueryString( array( 'type' => $this->type, 'key' => Settings::i()->ipb_reg_number ) );
if ( USE_DEVELOPMENT_BUILDS )
{
$url = $url->setQueryString( 'development', 1 );
}
if ( \IPS\IPS_ALPHA_BUILD )
if ( IPS_ALPHA_BUILD )
{
$url = $url->setQueryString( 'alpha', 1 );
}
@@ -62,31 +83,31 @@ class _updatecheck extends \IPS\Task
{
$response = $url->setQueryString( 'version', $version )->request()->get()->decodeJson();
$coreApp = \IPS\Application::load('core');
$coreApp = Application::load('core');
$coreApp->update_version = json_encode( $response );
$coreApp->update_last_check = time();
$coreApp->save();
/* Send a notification if new version is available */
if ( $updates = $coreApp->availableUpgrade() and \count( $updates ) )
if ( $updates = $coreApp->availableUpgrade( TRUE ) and count( $updates ) )
{
\IPS\core\AdminNotification::send( 'core', 'NewVersion', NULL, FALSE );
AdminNotification::send( 'core', 'NewVersion', NULL, FALSE );
}
else
{
\IPS\core\AdminNotification::remove( 'core', 'NewVersion' );
AdminNotification::remove( 'core', 'NewVersion' );
}
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
/* Check for bulletins while we're here */
try
{
$bulletins = \IPS\Http\Url::ips('bulletin')->request()->get()->decodeJson();
$bulletins = Url::ips('bulletin')->request()->get()->decodeJson();
foreach ( $bulletins as $id => $bulletin )
{
\IPS\Db::i()->insert( 'core_ips_bulletins', array(
Db::i()->insert( 'core_ips_bulletins', array(
'id' => $id,
'title' => $bulletin['title'],
@@ -108,36 +129,36 @@ class _updatecheck extends \IPS\Task
/* If the value is 0 for minVersion, there is no minimum version (a.k.a., display it). Same deal with maxVersion. */
( $bulletin['minVersion'] == 0 AND $bulletin['maxVersion'] == 0 )
/* If there's no minimum version, and the maximum Version is within range */
OR ( $bulletin['minVersion'] == 0 AND \IPS\Application::load('core')->long_version < $bulletin['maxVersion'] )
OR ( $bulletin['minVersion'] == 0 AND Application::load('core')->long_version < $bulletin['maxVersion'] )
/* If there's no maximum version, and the minimum version is within range */
OR ( $bulletin['maxVersion'] == 0 AND \IPS\Application::load('core')->long_version > $bulletin['minVersion'] )
OR ( $bulletin['maxVersion'] == 0 AND Application::load('core')->long_version > $bulletin['minVersion'] )
/* If both min and max versions are within range */
OR ( \IPS\Application::load('core')->long_version >= $bulletin['minVersion'] AND \IPS\Application::load('core')->long_version <= $bulletin['maxVersion'] )
OR ( Application::load('core')->long_version >= $bulletin['minVersion'] AND Application::load('core')->long_version <= $bulletin['maxVersion'] )
)
{
if ( @eval( $bulletin['conditions'] ) )
{
\IPS\core\AdminNotification::send( 'core', 'Bulletin', (string) $id, FALSE );
AdminNotification::send( 'core', 'Bulletin', (string) $id, FALSE );
}
else
{
\IPS\core\AdminNotification::remove( 'core', 'Bulletin', (string) $id );
AdminNotification::remove( 'core', 'Bulletin', (string) $id );
}
}
else
{
\IPS\core\AdminNotification::remove( 'core', 'Bulletin', (string) $id );
AdminNotification::remove( 'core', 'Bulletin', (string) $id );
}
}
catch ( \Throwable | \Exception $e )
catch ( Throwable | Exception $e )
{
\IPS\Log::log( $e, 'bulletin' );
Log::log( $e, 'bulletin' );
}
}
}
catch( \RuntimeException $e ){ }
catch( RuntimeException $e ){ }
$updateChecked = [];
$fails = [];
@@ -146,18 +167,17 @@ class _updatecheck extends \IPS\Task
$this->runUntilTimeout( function() use ( &$updateChecked, &$fails, $version, $fiveMinutesAgo ) {
try
{
$row = \IPS\Db::i()->union(
$row = Db::i()->union(
array(
\IPS\Db::i()->select( "'core_applications' AS `table`, app_directory AS `id`, app_update_check AS `url`, app_update_last_check AS `last`, app_long_version AS `current`", 'core_applications', "app_update_last_check<{$fiveMinutesAgo} AND ( app_update_check<>'' AND app_update_check IS NOT NULL )" ),
\IPS\Db::i()->select( "'core_plugins' AS `table`, plugin_id AS id, plugin_update_check as url, plugin_update_check_last AS last, plugin_version_long AS `current`", 'core_plugins', "plugin_update_check_last<{$fiveMinutesAgo} AND ( plugin_update_check<>'' AND plugin_update_check IS NOT NULL )" ),
\IPS\Db::i()->select( "'core_themes' AS `table`, set_id AS `id`, set_update_check AS `url`, set_update_last_check AS `last`, set_long_version AS `current`", 'core_themes', "set_update_last_check<{$fiveMinutesAgo} AND ( set_update_check<>'' AND set_update_check IS NOT NULL )" ),
\IPS\Db::i()->select( "'core_sys_lang' AS `table`, lang_id AS `id`, `lang_update_url` AS `url`, `lang_update_check` AS `last`, `lang_version_long` AS `current`", "core_sys_lang", "lang_update_check<{$fiveMinutesAgo} AND ( lang_update_url<>'' AND lang_update_url IS NOT NULL )" )
Db::i()->select( "'core_applications' AS `table`, app_directory AS `id`, app_update_check AS `url`, app_update_last_check AS `last`, app_long_version AS `current`", 'core_applications', "app_update_last_check<{$fiveMinutesAgo} AND ( app_update_check<>'' AND app_update_check IS NOT NULL )" ),
Db::i()->select( "'core_themes' AS `table`, set_id AS `id`, set_update_check AS `url`, set_update_last_check AS `last`, set_long_version AS `current`", 'core_themes', "set_update_last_check<{$fiveMinutesAgo} AND (set_update_check<>'' AND set_update_check IS NOT NULL )" ),
Db::i()->select( "'core_sys_lang' AS `table`, lang_id AS `id`, `lang_update_url` AS `url`, `lang_update_check` AS `last`, `lang_version_long` AS `current`", "core_sys_lang", "lang_update_check<{$fiveMinutesAgo} AND (lang_update_url<>'' AND lang_update_url IS NOT NULL )" )
),
'last ASC',
1
)->first();
}
catch( \UnderflowException $e )
catch( UnderflowException $e )
{
return FALSE;
}
@@ -174,28 +194,20 @@ class _updatecheck extends \IPS\Task
try
{
$key = "__app_{$row['id']}";
$source = \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( $key );
$source = Lang::load( Lang::defaultLanguage() )->get( $key );
}
catch ( \UnderflowException | \UnexpectedValueException $e )
catch ( UnderflowException | UnexpectedValueException $e )
{
return;
return null;
}
break;
case 'core_plugins':
$dataColumn = 'plugin_update_check_data';
$timeColumn = 'plugin_update_check_last';
$idColumn = 'plugin_id';
$source = \IPS\Plugin::load( $row['id'] )->name;
$updateChecked[] = 'plugins';
break;
case 'core_themes':
$dataColumn = 'set_update_data';
$timeColumn = 'set_update_last_check';
$idColumn = 'set_id';
$key = "core_theme_set_title_{$row['id']}";
$source = \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( $key );
$source = Lang::load( Lang::defaultLanguage() )->get( $key );
$updateChecked[] = 'themes';
break;
@@ -203,14 +215,14 @@ class _updatecheck extends \IPS\Task
$dataColumn = 'lang_update_data';
$timeColumn = 'lang_update_check';
$idColumn = 'lang_id';
$source = \IPS\Lang::load( $row['id'] )->_title;
$source = Lang::load( $row['id'] )->_title;
$updateChecked[] = 'languages';
break;
}
try
{
$url = \IPS\Http\Url::external( $row['url'] )->setQueryString( array( 'version' => $row['current'], 'ips_version' => $version ) );
$url = Url::external( $row['url'] )->setQueryString( array( 'version' => $row['current'], 'ips_version' => $version ) );
$response = $url->request()->get()->decodeJson();
/* Unset the object so it isn't present for next update check. */
@@ -219,28 +231,28 @@ class _updatecheck extends \IPS\Task
/* Did we get all the information we need? */
if ( !isset( $response['version'], $response['longversion'], $response['released'], $response['updateurl'] ) )
{
throw new \RuntimeException( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'update_check_missing' ) );
throw new RuntimeException( Lang::load( Lang::defaultLanguage() )->get( 'update_check_missing' ) );
}
/* Save the latest version data and move on to the next app */
\IPS\Db::i()->update( $row['table'], array(
Db::i()->update( $row['table'], array(
$dataColumn => json_encode( array(
'version' => $response['version'],
'longversion' => $response['longversion'],
'released' => $response['released'],
'updateurl' => $response['updateurl'],
'releasenotes' => isset( $response['releasenotes'] ) ? $response['releasenotes'] : NULL
'releasenotes' => $response['releasenotes'] ?? NULL
) ),
$timeColumn => time()
), array( "{$idColumn}=?", $row['id'] ) );
}
/* \RuntimeException catches BAD_JSON and \IPS\Http\Request\Exception both */
catch ( \RuntimeException $e )
catch ( RuntimeException $e )
{
$fails[] = $source . ": " . $e->getMessage();
/* Save the time so that the next time the task runs it can move on to other apps/plugins/themes */
\IPS\Db::i()->update( $row['table'], array(
Db::i()->update( $row['table'], array(
$timeColumn => time()
), array( "{$idColumn}=?", $row['id'] ) );
}
@@ -252,7 +264,7 @@ class _updatecheck extends \IPS\Task
foreach( $updateChecked as $type )
{
$key = 'updatecount_' . $type;
unset( \IPS\Data\Store::i()->$key, \IPS\Data\Store::i()->$type );
unset( Store::i()->$key, Store::i()->$type );
}
if ( !empty( $fails ) )
+65 -58
View File
@@ -11,16 +11,37 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Application;
use IPS\convert\App;
use IPS\Db;
use IPS\File;
use IPS\Http\Url;
use IPS\IPS;
use IPS\Lang;
use IPS\Login;
use IPS\nexus\Gateway;
use IPS\Settings;
use IPS\Task;
use IPS\Theme;
use function defined;
use function get_class;
use function in_array;
use function strpos;
use function strtolower;
use function substr;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* usagereporting Task
*/
class _usagereporting extends \IPS\Task
class usagereporting extends Task
{
/**
* Execute
@@ -31,19 +52,19 @@ class _usagereporting extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
/* Check usage reporting is enabled */
if ( !\IPS\Settings::i()->usage_reporting )
if ( !Settings::i()->usage_reporting )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
return NULL;
}
/* Check this isn't a test install */
$licenseData = \IPS\IPS::licenseKey();
$licenseData = IPS::licenseKey();
if ( \IPS\IN_DEV or !$licenseData or mb_substr( $licenseData['key'], -12 ) === '-TESTINSTALL' )
{
return NULL;
@@ -52,13 +73,13 @@ class _usagereporting extends \IPS\Task
/* Send the report */
try
{
$response = \IPS\Http\Url::external('https://invisionpowerdiagnostics.com/usage/')->request(2)->post( $this->buildReport() ); // Timeout is deliberately very low because we don't care if it times out (but not 0 because we still need to let the DNS resolve)
$response = Url::external('https://invisionpowerdiagnostics.com/usage/')->request(2)->post( $this->buildReport() ); // Timeout is deliberately very low because we don't care if it times out (but not 0 because we still need to let the DNS resolve)
/* If the server has asked us to stop sending reports, then turn it off */
if ( $response->httpResponseCode == 410 )
{
\IPS\Settings::i()->changeValues( array( 'usage_reporting' => 0 ) );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
Settings::i()->changeValues( array( 'usage_reporting' => 0 ) );
Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
}
}
catch ( \IPS\Http\Request\Exception $e )
@@ -74,33 +95,33 @@ class _usagereporting extends \IPS\Task
*
* @return array
*/
final protected function buildReport()
final protected function buildReport() : array
{
/* Identifier which allows us to keep separate reports from this community
from other reports (so we can see how communities change things as they grow) but
does NOT allow us to identify which community is sending the report */
$report = array( 'anonymized_id' => md5( \IPS\Settings::i()->base_url . \IPS\Settings::i()->site_secret_key ) );
$report = array( 'anonymized_id' => md5( Settings::i()->base_url . Settings::i()->site_secret_key ) );
/* Community data */
$licenseData = \IPS\IPS::licenseKey(); // this is just to know if it is *active* and if it is CiC - we don't actually send the license key
$licenseData = IPS::licenseKey(); // this is just to know if it is *active* and if it is CiC - we don't actually send the license key
$report['community'] = array(
'version' => \IPS\Application::load('core')->version,
'installed' => date( 'Y-m-d', \IPS\Settings::i()->board_start ),
'active_license'=> $licenseData ? ( (bool) $licenseData['active'] ) : FALSE,
'cloud' => $licenseData ? ( (bool) $licenseData['cloud'] ) : FALSE,
'version' => Application::load('core')->version,
'installed' => date( 'Y-m-d', Settings::i()->board_start ),
'active_license'=> $licenseData && $licenseData['active'],
'cloud' => $licenseData && $licenseData['cloud'],
);
/* Server Data */
$report['server'] = array(
'php_version' => PHP_VERSION_ID,
'php_extensions' => get_loaded_extensions(),
'mysql_version' => \IPS\Db::i()->server_version,
'mysql_version' => Db::i()->server_version,
'os' => PHP_OS,
);
/* Apps */
$report['apps'] = array();
foreach ( \IPS\Application::applications() as $app )
foreach ( Application::applications() as $app )
{
if ( $app->enabled )
{
@@ -108,41 +129,31 @@ class _usagereporting extends \IPS\Task
}
}
/* Plugins */
$report['plugins'] = array();
foreach ( \IPS\Plugin::plugins() as $plugin )
{
if ( $plugin->enabled )
{
$report['plugins'][ $plugin->location ] = $plugin->version_long;
}
}
/* Themes */
$report['themes'] = array();
foreach ( \IPS\Theme::themes() as $theme )
foreach ( Theme::themes() as $theme )
{
$settings = array();
foreach ( $theme->settings as $k => $v )
{
if ( \in_array( $k, array( 'responsive', 'rounded_photos', 'social_links', 'sidebar_position', 'sidebar_responsive', 'enable_fluid_width', 'fluid_width_size', 'js_incclude', 'ajax_pagination', 'cm_store_view', 'body_font', 'headline_font' ) ) )
if ( in_array( $k, array( 'responsive', 'rounded_photos', 'social_links', 'sidebar_position', 'sidebar_responsive', 'enable_fluid_width', 'fluid_width_size', 'js_incclude', 'ajax_pagination', 'cm_store_view', 'body_font', 'headline_font' ) ) )
{
$settings[ $k ] = $v;
}
}
$report['themes'][] = array(
'customised' => \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( 'template_set_id=?', $theme->id ) )->first(),
'customised' => Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( 'template_set_id=?', $theme->id ) )->first(),
'settings' => $settings,
);
}
/* Languages */
$report['languages'] = array();
foreach ( \IPS\Lang::languages() as $lang )
foreach ( Lang::languages() as $lang )
{
$localeDot = \strpos( $lang->short, '.' );
$langKey = $localeDot ? \substr( $lang->short, 0, $localeDot ) : $lang->short;
$localeDot = strpos( $lang->short, '.' );
$langKey = $localeDot ? substr( $lang->short, 0, $localeDot ) : $lang->short;
if ( !isset( $report['languages'][ $langKey ] ) )
{
@@ -152,9 +163,9 @@ class _usagereporting extends \IPS\Task
}
/* Settings */
foreach ( \IPS\Db::i()->select( array( 'conf_key', 'conf_value', 'conf_default', 'conf_app', 'conf_report' ), 'core_sys_conf_settings', 'conf_report IS NOT NULL' ) as $row )
foreach ( Db::i()->select( array( 'conf_key', 'conf_value', 'conf_default', 'conf_app', 'conf_report' ), 'core_sys_conf_settings', 'conf_report IS NOT NULL' ) as $row )
{
if ( \in_array( $row['conf_app'], \IPS\IPS::$ipsApps ) and \IPS\Application::appIsEnabled( $row['conf_app'] ) )
if ( in_array( $row['conf_app'], IPS::$ipsApps ) and Application::appIsEnabled( $row['conf_app'] ) )
{
if ( $row['conf_report'] == 'full' )
{
@@ -168,15 +179,15 @@ class _usagereporting extends \IPS\Task
}
/* Database counts */
foreach ( \IPS\IPS::$ipsApps as $app )
foreach ( IPS::$ipsApps as $app )
{
if ( \IPS\Application::appIsEnabled( $app ) and file_exists( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ) )
if ( Application::appIsEnabled( $app ) and file_exists( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ) )
{
foreach ( json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ), TRUE ) as $table => $data )
{
if ( isset( $data['reporting'] ) and $data['reporting'] === 'count' )
{
$report['tables'][ $table ] = \IPS\Db::i()->select( 'COUNT(*)', $table )->first();
$report['tables'][ $table ] = Db::i()->select( 'COUNT(*)', $table )->first();
}
}
}
@@ -184,11 +195,11 @@ class _usagereporting extends \IPS\Task
/* File storage configurations */
$report['files'] = array( 'amazon' => 0, 'database' => 0, 'filesystem' => 0, 'ftp' => 0, 'other' => 0 );
foreach ( \IPS\Application::allExtensions( 'core', 'FileStorage', FALSE ) as $k => $v )
foreach ( Application::allExtensions( 'core', 'FileStorage', FALSE ) as $k => $v )
{
try
{
$class = \strtolower( \substr( \get_class( \IPS\File::getClass( $k ) ), 9 ) );
$class = strtolower( substr( get_class( File::getClass( $k ) ), 9 ) );
if ( isset( $report['files'][ $class ] ) )
{
@@ -199,7 +210,7 @@ class _usagereporting extends \IPS\Task
$report['files']['other']++;
}
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
}
/* Login methods */
@@ -221,9 +232,9 @@ class _usagereporting extends \IPS\Task
$report['login'][ $v ] = 0;
}
$report['login']['other'] = 0;
foreach ( \IPS\Login::methods() as $method )
foreach ( Login::methods() as $method )
{
$class = \get_class( $method );
$class = get_class( $method );
if ( array_key_exists( $class, $loginMethods ) )
{
$report['login'][ $loginMethods[ $class ] ]++;
@@ -236,19 +247,15 @@ class _usagereporting extends \IPS\Task
/* Payment methods */
$report['paymethods'] = array();
if ( \IPS\Application::appIsEnabled('nexus') )
if ( Application::appIsEnabled('nexus') )
{
$report['paymethods'] = array( 'authorizenet_aim' => 0, 'authorizenet_dpm' => 0, 'manual' => 0, 'paypal_standard' => 0, 'paypal_pro' => 0, 'stripe_card' => 0, 'stripe_native' => 0, 'stripe_alipay' => 0, 'stripe_bancontact' => 0, 'stripe_giropay' => 0, 'stripe_ideal' => 0, 'stripe_sofort' => 0, 'test' => 0, 'twocheckout' => 0, 'other' => 0 );
foreach ( \IPS\nexus\Gateway::roots() as $gateway )
$report['paymethods'] = array( 'manual' => 0, 'paypal_standard' => 0, 'paypal_pro' => 0, 'stripe_card' => 0, 'stripe_native' => 0, 'stripe_alipay' => 0, 'stripe_bancontact' => 0, 'stripe_giropay' => 0, 'stripe_ideal' => 0, 'stripe_sofort' => 0, 'test' => 0, 'other' => 0 );
foreach ( Gateway::roots() as $gateway )
{
$class = \strtolower( \substr( \get_class( $gateway ), 18 ) );
$class = strtolower( substr( get_class( $gateway ), 18 ) );
$settings = json_decode( $gateway->settings, TRUE );
if ( $class === 'authorizenet' )
{
$class = ( $settings['method'] === 'AIM' ) ? 'authorizenet_aim' : 'authorizenet_dpm';
}
elseif ( $class === 'paypal' )
if ( $class === 'paypal' )
{
$class = ( $settings['type'] === 'paypal' ) ? 'paypal_standard' : 'paypal_pro';
}
@@ -271,12 +278,12 @@ class _usagereporting extends \IPS\Task
/* Converters */
$report['converters'] = array();
if ( \IPS\Application::appIsEnabled('convert') )
if ( Application::appIsEnabled('convert') )
{
foreach( \IPS\convert\App::apps() as $app )
foreach( App::apps() as $app )
{
/* Some legacy converters may not have the correct sw key */
if( !\in_array( $app->sw, \IPS\IPS::$ipsApps ) OR !$app->finished )
if( !in_array( $app->sw, IPS::$ipsApps ) OR !$app->finished )
{
continue;
}
+20 -11
View File
@@ -11,16 +11,25 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Http\Useragent;
use IPS\Session\Store;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* User agent statistics task
*/
class _userAgentStatistics extends \IPS\Task
class userAgentStatistics extends Task
{
/**
* Execute
@@ -31,28 +40,28 @@ class _userAgentStatistics extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$desktops = 0;
$tablets = 0;
$mobiles = 0;
$consoles = 0;
foreach( \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_MEMBERS, 'desc', NULL, NULL, TRUE, TRUE ) as $row )
foreach( Store::i()->getOnlineUsers( Store::ONLINE_MEMBERS, 'desc', NULL, NULL, TRUE, TRUE ) as $row )
{
$userAgent = \IPS\Http\Useragent::parse( $row['browser'] );
$userAgent = Useragent::parse( $row['browser'] );
if( \in_array( $userAgent->platform, array( 'iPhone', 'Windows Phone OS', 'BlackBerry', 'Android', 'Tizen' ) ) )
if( in_array( $userAgent->platform, array( 'iPhone', 'Windows Phone OS', 'BlackBerry', 'Android', 'Tizen' ) ) )
{
$mobiles++;
}
elseif( \in_array( $userAgent->platform, array( 'iPad / iPod Touch', 'Kindle', 'Kindle Fire', 'Playbook' ) ) )
elseif( in_array( $userAgent->platform, array( 'iPad / iPod Touch', 'Kindle', 'Kindle Fire', 'Playbook' ) ) )
{
$tablets++;
}
elseif( \in_array( $userAgent->platform, array( 'Nintendo 3DS', 'New Nintendo 3DS', 'Nintendo Wii', 'Nintendo WiiU', 'PlayStation 3', 'PlayStation 4', 'PlayStation Vita', 'Xbox 360', 'Xbox One' ) ) )
elseif( in_array( $userAgent->platform, array( 'Nintendo 3DS', 'New Nintendo 3DS', 'Nintendo Wii', 'Nintendo WiiU', 'PlayStation 3', 'PlayStation 4', 'PlayStation Vita', 'Xbox 360', 'Xbox One' ) ) )
{
$consoles++;
}
@@ -62,7 +71,7 @@ class _userAgentStatistics extends \IPS\Task
}
}
\IPS\Db::i()->insert( 'core_statistics', array(
Db::i()->insert( 'core_statistics', array(
'type' => 'devices',
'value_1' => $mobiles,
'value_2' => $tablets,
+98 -29
View File
@@ -11,17 +11,42 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\IPS;
use IPS\Db;
use IPS\Db\Exception;
use IPS\Log;
use IPS\Platform\Bridge;
use IPS\Redis;
use IPS\Task;
use OutOfRangeException;
use Throwable;
use UnderflowException;
use function defined;
use function in_array;
use function intval;
use function is_array;
use const IPS\CACHE_CONFIG;
use const IPS\CACHE_METHOD;
use const IPS\REDIS_CONFIG;
use const IPS\REDIS_ENABLED;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* view_updates Task
*/
class _viewupdates extends \IPS\Task
class viewupdates extends Task
{
/**
* @breif Stored data to send to Cloud in one go
*/
protected array $_sendToCloud = [];
/**
* Execute
*
@@ -31,17 +56,16 @@ class _viewupdates extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout(function(){
$hasCount = FALSE;
try
{
/* @note SELECT_FROM_WRITE_SERVER added in 72724569ca77f6686f6be0861ce673f793a862e8 to avoid a race condition that caused high view counts */
$database = \IPS\Db::i()->select( 'classname, id, count(*) AS count', 'core_view_updates', NULL, NULL, 20, array( 'classname', 'id' ), NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER );
$database = Db::i()->select( 'classname, id, count(*) AS count', 'core_view_updates', NULL, NULL, 20, array( 'classname', 'id' ), NULL, Db::SELECT_FROM_WRITE_SERVER );
/* Database results first */
foreach( $database as $row )
@@ -52,39 +76,42 @@ class _viewupdates extends \IPS\Task
{
$this->update( $row['classname'], $row['id'], $row['count'] );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException $e )
{
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=?', $row['classname'] ) );
Db::i()->delete( 'core_view_updates', array( 'classname=?', $row['classname'] ) );
}
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=? AND id=?', $row['classname'], $row['id'] ) );
Db::i()->delete( 'core_view_updates', array( 'classname=? AND id=?', $row['classname'], $row['id'] ) );
}
}
catch ( \UnderflowException $e ) { }
catch ( UnderflowException $e ) { }
/* Now do cloud */
Bridge::i()->viewTask( $this->_sendToCloud );
/* Now try redis */
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
if ( Redis::isEnabled() )
{
try
{
$redis = \IPS\Redis::i()->zRevRangeByScore( 'topic_views', '+inf', '-inf', array('withscores' => TRUE, 'limit' => array( 0, 20 ) ) );
$redis = Redis::i()->zRevRangeByScore( 'topic_views', '+inf', '-inf', array('withscores' => TRUE, 'limit' => array( 0, 20 ) ) );
if( \is_array( $redis ) AND \count( $redis ) )
if( is_array( $redis ) and count( $redis ) )
{
foreach ( $redis as $data => $count )
{
$hasCount = TRUE;
list( $class, $id ) = explode( '__', $data );
[ $class, $id ] = explode( '__', $data );
try
{
$this->update( $class, $id, \intval( $count ) );
$this->update( $class, $id, intval( $count ) );
}
catch ( \OutOfRangeException $e ) {}
catch ( OutOfRangeException $e ) {}
}
\IPS\Redis::i()->zRem( 'topic_views', ...array_keys( $redis ) );
Redis::i()->zRem( 'topic_views', ...array_keys( $redis ) );
}
}
catch( \Exception $e ) { }
@@ -92,9 +119,9 @@ class _viewupdates extends \IPS\Task
/* Now try advert impressions */
try
{
$redis = \IPS\Redis::i()->zRevRangeByScore( 'advert_impressions', '+inf', '-inf', array('withscores' => TRUE, 'limit' => array( 0, 20 ) ) );
$redis = Redis::i()->zRevRangeByScore( 'advert_impressions', '+inf', '-inf', array('withscores' => TRUE, 'limit' => array( 0, 20 ) ) );
if( \is_array( $redis ) )
if( is_array( $redis ) )
{
$updates = [];
foreach ( $redis as $id => $count )
@@ -102,12 +129,12 @@ class _viewupdates extends \IPS\Task
$hasCount = TRUE;
$updates[ $count ][] = $id;
\IPS\Redis::i()->zRem( 'advert_impressions', $id );
Redis::i()->zRem( 'advert_impressions', $id );
}
foreach ( $updates as $incrementBy => $ids )
{
\IPS\Db::i()->update( 'core_advertisements', "ad_impressions=ad_impressions+" . $incrementBy, [ \IPS\Db::i()->in( 'ad_id', $ids ) ] );
Db::i()->update( 'core_advertisements', "ad_impressions=ad_impressions+" . $incrementBy, [ Db::i()->in( 'ad_id', $ids ) ] );
}
}
}
@@ -124,6 +151,8 @@ class _viewupdates extends \IPS\Task
return FALSE;
}
});
return null;
}
/**
@@ -132,26 +161,66 @@ class _viewupdates extends \IPS\Task
* @param string $class Class to update
* @param int $id ID of item
* @param int $count Count to update
* @throws \OutOfRangeException When table to update no longer exists
* @throws OutOfRangeException When table to update no longer exists
*/
protected function update( $class, $id, $count )
protected function update( string $class, int $id, int $count ) : void
{
if ( class_exists( $class ) and \IPS\IPS::classUsesTrait( $class, 'IPS\Content\ViewUpdates' ) AND isset( $class::$databaseColumnMap['views'] ) )
if ( class_exists( $class ) and IPS::classUsesTrait( $class, 'IPS\Content\ViewUpdates' ) AND isset( $class::$databaseColumnMap['views'] ) )
{
try
{
\IPS\Db::i()->update(
$item = $class::load( $id );
$title = '';
/* If we specify a title specifically for analytics, use that always. */
if ( method_exists( $item, 'titleForAnalytics' ) )
{
$title = $item->titleForAnalytics();
}
/* Otherwise use titleForLog for Nodes */
else if ( in_array( 'IPS\Node\Model', class_parents( $item ) ) )
{
$title = $item->titleForLog();
}
/* Or the defined title column for content items. */
else if ( in_array( 'IPS\Content\Item', class_parents( $item ) ) )
{
$title = $item->mapped('title');
}
$url = '';
if ( method_exists( $item, 'url' ) )
{
$url = $item->url();
}
$this->_sendToCloud[] = [
'contentClass' => $class,
'contentId' => $id,
'views' => $count,
'title' => $title,
'url' => (string) $url
];
}
catch( Throwable $e )
{
Log::log( $e, 'views' );
}
try
{
Db::i()->update(
$class::$databaseTable,
"`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`=`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`+{$count}",
array( "{$class::$databasePrefix}{$class::$databaseColumnId}=?", $id )
);
}
catch( \IPS\Db\Exception $e )
catch( Exception $e )
{
/* Table to update no longer exists */
if( $e->getCode() == 1146 )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
throw $e;
+38 -24
View File
@@ -11,16 +11,29 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use Exception;
use IPS\Application;
use IPS\Db;
use IPS\Http\Url;
use IPS\IPS;
use IPS\Output;
use IPS\Settings;
use IPS\Task;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* webhooks Task
*/
class _webhooks extends \IPS\Task
class webhooks extends Task
{
/**
* Execute
@@ -31,36 +44,35 @@ class _webhooks extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Task\Exception
*/
public function execute()
public function execute() : mixed
{
/* Get our webhooks */
$webhooks = iterator_to_array( \IPS\Db::i()->select( '*', 'core_api_webhooks', array('enabled=1') )->setKeyField('id') );
$webhooks = iterator_to_array( Db::i()->select( '*', 'core_api_webhooks', array('enabled=1') )->setKeyField('id') );
/* Run through the queue */
$this->runUntilTimeout( function() use ( $webhooks ) {
/* Try and get a queue item */
try
{
/* @note SELECT_FROM_WRITE_SERVER race condition in tasks */
$fire = \IPS\Db::i()->select( '*', 'core_api_webhook_fires', array( "status='pending'" ), '`time` ASC', 1, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$fire = Db::i()->select( '*', 'core_api_webhook_fires', array( "status='pending'" ), '`time` ASC', 1, NULL, NULL, Db::SELECT_FROM_WRITE_SERVER )->first();
try
{
if ( !isset( $webhooks[ $fire['webhook'] ] ) )
{
throw new \DomainException("Webhook Disabled");
throw new DomainException("Webhook Disabled");
}
\IPS\Output::i()->parseFileObjectUrls( $fire['data'] );
$fire['data'] = \IPS\Output::i()->replaceEmojiWithImages( $fire['data'] );
$request = \IPS\Http\Url::external( $webhooks[ $fire['webhook'] ]['url'] )
Output::i()->parseFileObjectUrls( $fire['data'] );
$fire['data'] = Output::i()->replaceEmojiWithImages( $fire['data'] );
$request = Url::external( $webhooks[ $fire['webhook'] ]['url'] )
->request()
->setHeaders(
[
'User-Agent' => "InvisionCommunity/" . \IPS\Application::load('core')->long_version ,
'User-Agent' => "InvisionCommunity/" . Application::load('core')->long_version ,
'Webhook-Event' => $fire['event'],
'Content-Type' => $webhooks[ $fire['webhook'] ]['content_type']
]
@@ -73,9 +85,9 @@ class _webhooks extends \IPS\Task
$response = $request->post( $fire['data'] );
if ( \IPS\Settings::i()->webhook_logs_success )
if ( Settings::i()->webhook_logs_success )
{
\IPS\Db::i()->update( 'core_api_webhook_fires', [
Db::i()->update( 'core_api_webhook_fires', [
'status' => 'successful',
'response_code' => $response->httpResponseCode,
'response_body' => $response->content
@@ -83,41 +95,43 @@ class _webhooks extends \IPS\Task
}
else
{
\IPS\Db::i()->delete( 'core_api_webhook_fires', [ 'id=?', $fire['id'] ] );
Db::i()->delete( 'core_api_webhook_fires', [ 'id=?', $fire['id'] ] );
}
}
catch ( \Exception $e )
catch ( Exception $e )
{
$update = [
'response_code' => NULL,
'response_body' => \IPS\IPS::getExceptionDetails( $e ),
'response_body' => IPS::getExceptionDetails( $e ),
'fails' => $fire['fails'] + 1,
];
if ( $fire['fails'] >= ( \IPS\Settings::i()->webhooks_allowed_fails - 1 ) )
if ( $fire['fails'] >= ( Settings::i()->webhooks_allowed_fails - 1 ) )
{
$update['status'] = 'failed';
}
if ( isset( $update['status'] ) and $update['status'] === 'failed' and !\IPS\Settings::i()->webhook_logs_fail )
if ( isset( $update['status'] ) and $update['status'] === 'failed' and !Settings::i()->webhook_logs_fail )
{
\IPS\Db::i()->delete( 'core_api_webhook_fires', [ 'id=?', $fire['id'] ] );
Db::i()->delete( 'core_api_webhook_fires', [ 'id=?', $fire['id'] ] );
}
else
{
\IPS\Db::i()->update( 'core_api_webhook_fires', $update, [ 'id=?', $fire['id'] ] );
Db::i()->update( 'core_api_webhook_fires', $update, [ 'id=?', $fire['id'] ] );
}
}
return TRUE;
}
/* If there's no queue items left, disable this task and return */
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
$this->enabled = FALSE;
$this->save();
return FALSE;
}
});
return null;
}
/**
+21 -9
View File
@@ -12,16 +12,26 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\DateTime;
use IPS\Db;
use IPS\Settings;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* weeklyCleanup Task
*/
class _weeklyCleanup extends \IPS\Task
class weeklyCleanup extends Task
{
/**
* Execute
@@ -32,14 +42,14 @@ class _weeklyCleanup extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* If we are currently pruning any large tables via a bg task, find out so we don't try to prune them normally here as well. The bg task should finish first. */
$currentlyPruning = array();
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( '`key`=?', 'PruneLargeTable' ) ) as $pruneTask )
foreach( Db::i()->select( '*', 'core_queue', array( '`key`=?', 'PruneLargeTable' ) ) as $pruneTask )
{
$data = json_decode( $pruneTask['data'], true );
@@ -47,13 +57,15 @@ class _weeklyCleanup extends \IPS\Task
}
/* Delete old follows */
if ( \IPS\Settings::i()->prune_follows AND !\in_array( 'core_follow', $currentlyPruning ) )
if ( Settings::i()->prune_follows AND !in_array( 'core_follow', $currentlyPruning ) )
{
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app!=? AND follow_area!=? AND follow_member_id IN(?)', 'core', 'member', \IPS\Db::i()->select( 'member_id', 'core_members', array( 'last_activity < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_follows . 'D' ) )->getTimestamp() ) ) ) );
Db::i()->delete( 'core_follow', array( 'follow_app!=? AND follow_area!=? AND follow_member_id IN(?)', 'core', 'member', Db::i()->select( 'member_id', 'core_members', array( 'last_activity < ?', DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->prune_follows . 'D' ) )->getTimestamp() ) ) ) );
/* And clear the cache so it can rebuild */
\IPS\Db::i()->delete( 'core_follow_count_cache' );
Db::i()->delete( 'core_follow_count_cache' );
}
return null;
}
/**
@@ -11,16 +11,23 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\core\Stream\Subscription;
use IPS\Db;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* weeklyStreamSubscriptions Task
*/
class _weeklyStreamSubscriptions extends \IPS\Task
class weeklyStreamSubscriptions extends Task
{
/**
* Execute
@@ -31,12 +38,12 @@ class _weeklyStreamSubscriptions extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
/* Disable task if no subscriptions */
$select = \IPS\Db::i()->select( '*', 'core_stream_subscriptions', array( 'frequency=?', 'weekly' ));
$select = Db::i()->select( '*', 'core_stream_subscriptions', array( 'frequency=?', 'weekly' ));
if( !$select->count() )
{
$this->enabled = FALSE;
@@ -47,7 +54,7 @@ class _weeklyStreamSubscriptions extends \IPS\Task
$this->runUntilTimeout( function()
{
return \IPS\core\Stream\Subscription::sendBatch( 'weekly' );
return Subscription::sendBatch( 'weekly' );
});
return NULL;
}
+12 -6
View File
@@ -11,16 +11,22 @@
namespace IPS\core\tasks;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\core\Digest\Digest;
use IPS\Task;
use IPS\Task\Exception;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* digest Task
*/
class _weeklydigest extends \IPS\Task
class weeklydigest extends Task
{
/**
* Execute
@@ -31,13 +37,13 @@ class _weeklydigest extends \IPS\Task
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
* @throws Exception
*/
public function execute()
public function execute() : mixed
{
$this->runUntilTimeout( function()
{
return \IPS\core\Digest\Digest::sendDigestBatch( 'weekly' );
return Digest::sendDigestBatch( 'weekly' );
});
return NULL;