File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/LinkStatus.php.tar
uyarreklam.com.tr/httpdocs/wp-content/plugins/broken-link-checker-seo/app/Models/LinkStatus.php 0000644 00000017775 15154303134 0031651 0 ustar 00 var/www/vhosts <?php
namespace AIOSEO\BrokenLinkChecker\Models;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\BrokenLinkChecker\Core\Database;
/**
* The LinkStatus DB model class.
*
* @since 1.0.0
*/
class LinkStatus extends Model {
/**
* The name of the table in the database, without the prefix.
*
* @since 1.0.0
*
* @var string
*/
protected $table = 'aioseo_blc_link_status';
/**
* Fields that should be numeric values.
*
* @since 1.0.0
*
* @var array
*/
protected $integerFields = [ 'id', 'broken', 'dismissed', 'scan_count', 'redirect_count', 'http_status_code' ];
/**
* Fields that are nullable.
*
* @since 1.0.0
*
* @var array
*/
protected $nullFields = [ 'last_scan_date', 'final_url' ];
/**
* Fields that should be boolean values.
*
* @since 1.0.0
*
* @var array
*/
protected $booleanFields = [
'broken',
'dismissed'
];
/**
* Fields that contain a JSON string.
*
* @since 1.0.0
*
* @var array
*/
protected $jsonFields = [ 'log' ];
/**
* Returns the Link Status with the given ID.
*
* @since 1.0.0
*
* @param int $linkStatusId The Link Status ID.
* @return LinkStatus The Link Status instance.
*/
public static function getById( $linkStatusId ) {
return aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status' )
->where( 'id', $linkStatusId )
->run()
->model( 'AIOSEO\\BrokenLinkChecker\\Models\\LinkStatus' );
}
/**
* Returns a list of Link Status rows with the given IDs.
*
* @since 1.1.0
*
* @param array $linkStatusIds List of Link Status IDs.
* @return array List of Link Status instances.
*/
public static function getByIds( $linkStatusIds ) {
return aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status' )
->whereIn( 'id', $linkStatusIds )
->run()
->models( 'AIOSEO\\BrokenLinkChecker\\Models\\LinkStatus' );
}
/**
* Returns the Link Status with the given URL.
*
* @since 1.0.0
*
* @param string $url The URL (unhashed!).
* @return LinkStatus The Link Status instance.
*/
public static function getByUrl( $url ) {
$hash = sha1( $url );
$linkStatus = aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status' )
->where( 'url_hash', $hash )
->run()
->model( 'AIOSEO\\BrokenLinkChecker\\Models\\LinkStatus' );
if ( ! $linkStatus->exists() ) {
// Updates to the plugin can cause hash mismatches. Let's do another attempt using the URL.
// We do a join to improve performance since the URL isn't indexed.
$hostname = wp_parse_url( $url, PHP_URL_HOST );
$result = aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status as abls' )
->select( 'abls.id' )
->join( 'aioseo_blc_links as abl', 'abls.id = abl.blc_link_status_id' )
->where( 'abl.hostname', $hostname )
->where( 'abls.url', $url )
->groupBy( 'abls.id' )
->limit( 1 )
->run()
->result();
if ( ! empty( $result[0]->id ) ) {
$linkStatus = self::getById( $result[0]->id );
if ( $linkStatus->exists() ) {
// Reset the URL hash to prevent future mismatches.
$linkStatus->url_hash = $hash;
$linkStatus->save();
}
}
}
return $linkStatus;
}
/**
* Returns all broken links for a given post ID.
*
* @since 1.2.0
*
* @param int $postId The post ID.
* @return array The list of broken links.
*/
public static function getBrokenByPostId( $postId ) {
$query = aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status as als' )
->join( 'aioseo_blc_links as al', 'als.id = al.blc_link_status_id' )
->where( 'al.post_id', $postId )
->where( 'als.broken', true )
->where( 'als.dismissed', false );
return $query->run()
->result();
}
/**
* Returns link status row results based on the given arguments.
* This is basically a wrapper/query builder that we use to fetch all the data we need for the Broken Links Report.
*
* @since 1.0.0
* @version 1.1.0 Moved from Links model to Link Status model.
*
* @param string $filter The active filter.
* @param int $limit The limit.
* @param int $offset The offset.
* @param string $whereClause The WHERE clause.
* @param string $orderBy The order by.
* @param string $orderDir The order direction.
* @return array List of Link Status rows with related Link rows embedded.
*/
public static function rowQuery( $filter = 'all', $limit = 20, $offset = 0, $whereClause = '', $orderBy = '', $orderDir = 'DESC' ) {
$query = self::baseQuery( $filter, $whereClause )
->select( 'als.*, al.external' )
->limit( $limit, $offset );
if ( $orderBy && $orderDir ) {
$query->orderBy( "$orderBy $orderDir" );
} else {
$query->orderBy( 'als.id DESC' );
}
$linkStatusRows = $query->run()
->result();
if ( empty( $linkStatusRows ) ) {
return [];
}
$rowsWithData = [];
foreach ( $linkStatusRows as $linkStatusRow ) {
$linkStatusRow->totalLinks = Link::rowQueryCount( $linkStatusRow->id );
if ( $linkStatusRow->totalLinks > 1 ) {
$rowsWithData[] = $linkStatusRow;
continue;
}
// If this link status has just one link, then we'll get it here.
// Otherwise we'll get them when the links table loads.
$linkRows = Link::rowQuery( $linkStatusRow->id, 1 );
$linkStatusRow->link = reset( $linkRows );
$rowsWithData[] = $linkStatusRow;
}
return $rowsWithData;
}
/**
* Returns link status row count based on the given arguments.
* This is basically a wrapper/query builder that we use to fetch all the counts we need for the Broken Links Report.
*
* @since 1.0.0
* @version 1.1.0 Moved from Links model to Link Status model.
*
* @param string $filter The active filter.
* @param string $whereClause The WHERE clause.
* @return int The row count.
*/
public static function rowCountQuery( $filter = 'all', $whereClause = '' ) {
$query = self::baseQuery( $filter, $whereClause );
return $query->count();
}
/**
* Returns the base query for the rowQuery() and rowCountQuery() methods.
*
* @since 1.0.0
* @version 1.1.0 Moved from Links model to Link Status model.
*
* @param string $filter The active filter.
* @param string $whereClause The WHERE clause.
* @return Database The query.
*/
private static function baseQuery( $filter = 'all', $whereClause = '' ) {
$includedPostTypes = aioseoBrokenLinkChecker()->helpers->getIncludedPostTypes();
$includedPostStatuses = aioseoBrokenLinkChecker()->helpers->getIncludedPostStatuses();
$excludedPostIds = aioseoBrokenLinkChecker()->helpers->getExcludedPostIds();
$excludedDomains = aioseoBrokenLinkChecker()->helpers->getExcludedDomains();
$query = aioseoBrokenLinkChecker()->core->db->start( 'aioseo_blc_link_status as als' )
->join( 'aioseo_blc_links as al', 'als.id = al.blc_link_status_id' )
->join( 'posts as p', 'al.post_id = p.ID' )
->groupBy( 'al.url' );
if ( ! empty( $whereClause ) ) {
$query->whereRaw( $whereClause );
}
if ( ! empty( $includedPostStatuses ) ) {
$query->whereIn( 'p.post_status', $includedPostStatuses );
}
if ( ! empty( $includedPostTypes ) ) {
$query->whereIn( 'p.post_type', $includedPostTypes );
}
if ( ! empty( $excludedPostIds ) ) {
$query->whereNotIn( 'p.ID', $excludedPostIds );
}
if ( ! empty( $excludedDomains ) ) {
$query->whereNotIn( 'al.hostname', $excludedDomains );
}
if ( ! empty( $filter ) ) {
switch ( $filter ) {
case 'broken':
$query->where( 'als.broken', true );
$query->where( 'als.dismissed', false );
break;
case 'redirects':
$query->where( 'als.redirect_count >', 0 );
$query->where( 'als.dismissed', false );
break;
case 'dismissed':
$query->where( 'als.dismissed', true );
break;
case 'not-checked':
$query->where( 'als.last_scan_date', null );
break;
case 'all':
default:
$query->where( 'als.dismissed', false );
break;
}
}
return $query;
}
} uyarreklam.com.tr/httpdocs/wp-content/plugins/broken-link-checker-seo/app/LinkStatus/LinkStatus.php 0000644 00000024347 15154336456 0032535 0 ustar 00 var/www/vhosts <?php
namespace AIOSEO\BrokenLinkChecker\LinkStatus;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\BrokenLinkChecker\Models;
/**
* Handles the Link Status scan.
*
* @since 1.0.0
*/
class LinkStatus {
/**
* The base URL for the broken link checker server.
*
* @since 1.0.0
*
* @var string
*/
private $baseUrl = 'https://check-links.aioseo.com/v1/';
/**
* The action name of the scan.
*
* @since 1.0.0
*
* @var string
*/
public $actionName = 'aioseo_blc_link_status_scan';
/**
* Data class instance.
*
* @since 1.1.0
*
* @var Data
*/
public $data = null;
/**
* Class constructor.
*
* @since 1.0.0
*/
public function __construct() {
$this->data = new Data();
add_action( $this->actionName, [ $this, 'checkLinkStatuses' ], 11, 1 );
if ( ! is_admin() ) {
return;
}
add_action( 'init', [ $this, 'scheduleScan' ], 3003 );
}
/**
* Schedules the link status scan.
*
* @since 1.0.0
*
* @return void
*/
public function scheduleScan() {
if ( ! aioseoBrokenLinkChecker()->license->isActive() ) {
return;
}
// If there is no action at all, schedule one.
if ( ! aioseoBrokenLinkChecker()->actionScheduler->isScheduled( $this->actionName ) ) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleAsync( $this->actionName );
}
}
/**
* Sends links to the server to check their status.
*
* @since 1.0.0
*
* @return void
*/
public function checkLinkStatuses() {
if ( ! aioseoBrokenLinkChecker()->license->isActive() ) {
return;
}
$scanId = aioseoBrokenLinkChecker()->internalOptions->internal->scanId;
if ( ! empty( $scanId ) ) {
// If we have a scan ID, check if the results are ready.
$this->checkForScanResults();
return;
}
// If we don't have a scan ID, first check if there are links that need to be checked.
$linksToCheck = $this->data->getlinksToCheck();
if ( empty( $linksToCheck ) ) {
// If there are no links to check, wait 15 minutes.
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, 15 * MINUTE_IN_SECONDS );
return;
}
// If there are links to check, start a new scan.
$this->startScan();
}
/**
* Start a scan and store the scan ID.
*
* @since 1.0.0
*
* @return void
*/
private function startScan() {
$requestBody = array_merge(
$this->data->getBaseData(),
[
'links' => $this->data->getlinksToCheck()
]
);
$response = $this->doPostRequest( 'scan/start/', $requestBody );
$responseCode = (int) wp_remote_retrieve_response_code( $response );
if ( 401 === $responseCode ) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, DAY_IN_SECONDS + wp_rand( 60, 600 ) );
return;
}
if ( 418 === $responseCode ) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, HOUR_IN_SECONDS + wp_rand( 60, 600 ) );
return;
}
$responseBody = json_decode( wp_remote_retrieve_body( $response ) );
if (
is_wp_error( $response ) ||
200 !== $responseCode ||
empty( $responseBody->success ) ||
empty( $responseBody->scanId ) ||
! isset( $responseBody->quotaRemaining )
) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, MINUTE_IN_SECONDS );
return;
}
aioseoBrokenLinkChecker()->internalOptions->internal->scanId = $responseBody->scanId;
aioseoBrokenLinkChecker()->internalOptions->internal->license->quotaRemaining = $responseBody->quotaRemaining;
if ( aioseoBrokenLinkChecker()->internalOptions->internal->license->quota !== $responseBody->quota ) {
// If the quota changed, reactivate the license to pull in the latest date from the marketing site.
aioseoBrokenLinkChecker()->internalOptions->internal->license->quota = $responseBody->quota;
aioseoBrokenLinkChecker()->license->activate();
}
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, MINUTE_IN_SECONDS );
}
/**
* Checks if the scan has been completed. If so, parses and stores the results.
*
* @since 1.0.0
*
* @return void
*/
private function checkForScanResults() {
$scanId = aioseoBrokenLinkChecker()->internalOptions->internal->scanId;
if ( empty( $scanId ) ) {
return;
}
$response = $this->doPostRequest( "scan/{$scanId}/" );
$responseCode = (int) wp_remote_retrieve_response_code( $response );
if ( 401 === $responseCode ) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, DAY_IN_SECONDS + wp_rand( 60, 600 ) );
return;
}
if ( 418 === $responseCode ) {
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, HOUR_IN_SECONDS + wp_rand( 60, 600 ) );
return;
}
$responseBody = json_decode( wp_remote_retrieve_body( $response ) );
if ( is_wp_error( $response ) && 200 !== $responseCode || empty( $responseBody->success ) ) {
// If the scan data cannot be found on the server, wipe the scan ID so the scan restarts.
if ( ! empty( $responseBody->error ) && 'missing-scan-data' === strtolower( $responseBody->error ) ) {
aioseoBrokenLinkChecker()->internalOptions->internal->scanId = '';
}
aioseoBrokenLinkChecker()->actionScheduler->scheduleSingle( $this->actionName, MINUTE_IN_SECONDS );
return;
}
$this->parseResults( $responseBody );
aioseoBrokenLinkChecker()->internalOptions->internal->license->quotaRemaining = $responseBody->quotaRemaining;
if ( aioseoBrokenLinkChecker()->internalOptions->internal->license->quota !== $responseBody->quota ) {
// If the quota changed, reactivate the license to pull in the latest date from the marketing site.
aioseoBrokenLinkChecker()->internalOptions->internal->license->quota = $responseBody->quota;
aioseoBrokenLinkChecker()->license->activate();
}
// Once the request is successful, we know the scan has been completed and we can go ahead and reset it.
$this->doDeleteRequest( "scan/{$scanId}/" );
aioseoBrokenLinkChecker()->internalOptions->internal->scanId = '';
}
/**
* Parse the results that came back from the server.
*
* @since 1.0.0
*
* @param Object $responseBody The response body object.
* @return void
*/
private function parseResults( $responseBody ) {
$scanData = json_decode( $responseBody->scanData );
if ( empty( $scanData ) || empty( $scanData->urls ) ) {
return;
}
foreach ( $scanData->urls as $url ) {
$this->parseResultsHelper( $url );
}
}
/**
* Helper function for parseResults().
*
* @since 1.0.0
*
* @param Object $url The URL object.
* @return void
*/
public function parseResultsHelper( $url ) {
$linkStatus = Models\LinkStatus::getByUrl( $url->url );
if ( ! $linkStatus->exists() || empty( $url->data ) ) {
return;
}
if ( empty( $url->data->status ) ) {
$linkStatus->scanning = false;
$linkStatus->broken = true;
$linkStatus->http_status_code = null;
$linkStatus->request_duration = 0;
$linkStatus->final_url = '';
$linkStatus->scan_count = $linkStatus->scan_count + 1;
$linkStatus->last_scan_date = aioseoBrokenLinkChecker()->helpers->timeToMysql( time() );
$linkStatus->log = [
'error' => ! empty( $url->data->error ) ? $url->data->error : '',
'headers' => ! empty( $url->data->headers ) ? $url->data->headers : ''
];
if ( ! $linkStatus->first_failure ) {
$linkStatus->first_failure = aioseoBrokenLinkChecker()->helpers->timeToMysql( time() );
}
$linkStatus->save();
return;
}
$success = (int) $url->data->status < 400;
$redirectCount = count( $url->data->redirects );
$finalUrl = $redirectCount ? $url->data->redirects[ $redirectCount - 1 ] : '';
$linkStatus->scanning = false;
$linkStatus->broken = ! $success;
$linkStatus->http_status_code = (int) $url->data->status;
$linkStatus->redirect_count = $redirectCount;
$linkStatus->final_url = $finalUrl;
$linkStatus->request_duration = ! empty( $url->data->stats->loadTime ) ? abs( $url->data->stats->loadTime ) : 0;
$linkStatus->scan_count = $linkStatus->scan_count + 1;
$linkStatus->last_scan_date = aioseoBrokenLinkChecker()->helpers->timeToMysql( time() );
$linkStatus->log = [
'error' => ! empty( $url->data->error ) ? $url->data->error : '',
'headers' => ! empty( $url->data->headers ) ? $url->data->headers : ''
];
if ( $success ) {
$linkStatus->last_success = aioseoBrokenLinkChecker()->helpers->timeToMysql( time() );
$linkStatus->first_failure = null;
} elseif ( ! $linkStatus->first_failure ) {
$linkStatus->first_failure = aioseoBrokenLinkChecker()->helpers->timeToMysql( time() );
}
$linkStatus->save();
}
/**
* Returns the URL for the Broken Link Checker server.
*
* @since 1.0.0
*
* @return string The URL.
*/
public function getUrl() {
if ( defined( 'AIOSEO_BROKEN_LINK_CHECKER_SCAN_URL' ) ) {
return AIOSEO_BROKEN_LINK_CHECKER_SCAN_URL;
}
return $this->baseUrl;
}
/**
* Sends a POST request to the server.
*
* @since 1.0.0
*
* @param string $path The path.
* @param array $requestBody The request body.
* @return array|\WP_Error The response or WP_Error on failure.
*/
public function doPostRequest( $path, $requestBody = [] ) {
$requestData = [
'headers' => [
'X-AIOSEO-BLC-License' => aioseoBrokenLinkChecker()->internalOptions->internal->license->licenseKey,
'Content-Type' => 'application/json'
],
'timeout' => 60
];
if ( ! empty( $requestBody ) ) {
$requestData['body'] = wp_json_encode( $requestBody );
}
$baseUrl = $this->getUrl();
$response = wp_remote_post( $baseUrl . $path, $requestData );
return $response;
}
/**
* Sends a DELETE request to the server.
*
* @since 1.0.0
*
* @param string $path The path.
* @return array|\WP_Error The response or WP_Error on failure.
*/
public function doDeleteRequest( $path ) {
$requestData = [
'method' => 'DELETE',
'headers' => [
'X-AIOSEO-BLC-License' => aioseoBrokenLinkChecker()->internalOptions->internal->license->licenseKey,
'Content-Type' => 'application/json'
],
'timeout' => 60
];
$baseUrl = $this->getUrl();
$response = wp_remote_request( $baseUrl . $path, $requestData );
return $response;
}
}