MediaWiki  1.34.0
Pingback.php
Go to the documentation of this file.
1 <?php
23 use Psr\Log\LoggerInterface;
26 
32 class Pingback {
33 
39  const SCHEMA_REV = 15781718;
40 
42  protected $logger;
43 
45  protected $config;
46 
48  protected $key;
49 
51  protected $id;
52 
57  public function __construct( Config $config = null, LoggerInterface $logger = null ) {
58  $this->config = $config ?: RequestContext::getMain()->getConfig();
59  $this->logger = $logger ?: LoggerFactory::getInstance( __CLASS__ );
60  $this->key = 'Pingback-' . $this->config->get( 'Version' );
61  }
62 
67  private function shouldSend() {
68  return $this->config->get( 'Pingback' ) && !$this->checkIfSent();
69  }
70 
75  private function checkIfSent() {
76  $dbr = wfGetDB( DB_REPLICA );
77  $timestamp = $dbr->selectField(
78  'updatelog',
79  'ul_value',
80  [ 'ul_key' => $this->key ],
81  __METHOD__
82  );
83  if ( $timestamp === false ) {
84  return false;
85  }
86  // send heartbeat ping if last ping was over a month ago
87  if ( time() - (int)$timestamp > 60 * 60 * 24 * 30 ) {
88  return false;
89  }
90  return true;
91  }
92 
97  private function markSent() {
98  $dbw = wfGetDB( DB_MASTER );
99  $timestamp = time();
100  return $dbw->upsert(
101  'updatelog',
102  [ 'ul_key' => $this->key, 'ul_value' => $timestamp ],
103  [ 'ul_key' ],
104  [ 'ul_value' => $timestamp ],
105  __METHOD__
106  );
107  }
108 
117  private function acquireLock() {
119  if ( !$cache->add( $this->key, 1, 60 * 60 ) ) {
120  return false; // throttled
121  }
122 
123  $dbw = wfGetDB( DB_MASTER );
124  if ( !$dbw->lock( $this->key, __METHOD__, 0 ) ) {
125  return false; // already in progress
126  }
127 
128  return true;
129  }
130 
143  public function getSystemInfo() {
144  $event = [
145  'database' => $this->config->get( 'DBtype' ),
146  'MediaWiki' => $this->config->get( 'Version' ),
147  'PHP' => PHP_VERSION,
148  'OS' => PHP_OS . ' ' . php_uname( 'r' ),
149  'arch' => PHP_INT_SIZE === 8 ? 64 : 32,
150  'machine' => php_uname( 'm' ),
151  ];
152 
153  if ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
154  $event['serverSoftware'] = $_SERVER['SERVER_SOFTWARE'];
155  }
156 
157  $limit = ini_get( 'memory_limit' );
158  if ( $limit && $limit != -1 ) {
159  $event['memoryLimit'] = $limit;
160  }
161 
162  return $event;
163  }
164 
170  private function getData() {
171  return [
172  'schema' => 'MediaWikiPingback',
173  'revision' => self::SCHEMA_REV,
174  'wiki' => $this->getOrCreatePingbackId(),
175  'event' => $this->getSystemInfo(),
176  ];
177  }
178 
187  private function getOrCreatePingbackId() {
188  if ( !$this->id ) {
189  $id = wfGetDB( DB_REPLICA )->selectField(
190  'updatelog', 'ul_value', [ 'ul_key' => 'PingBack' ] );
191 
192  if ( $id == false ) {
194  $dbw = wfGetDB( DB_MASTER );
195  $dbw->insert(
196  'updatelog',
197  [ 'ul_key' => 'PingBack', 'ul_value' => $id ],
198  __METHOD__,
199  [ 'IGNORE' ]
200  );
201 
202  if ( !$dbw->affectedRows() ) {
203  $id = $dbw->selectField(
204  'updatelog', 'ul_value', [ 'ul_key' => 'PingBack' ] );
205  }
206  }
207 
208  $this->id = $id;
209  }
210 
211  return $this->id;
212  }
213 
229  private function postPingback( array $data ) {
230  $json = FormatJson::encode( $data );
231  $queryString = rawurlencode( str_replace( ' ', '\u0020', $json ) ) . ';';
232  $url = 'https://www.mediawiki.org/beacon/event?' . $queryString;
233  return MediaWikiServices::getInstance()->getHttpRequestFactory()->post( $url ) !== null;
234  }
235 
251  public function sendPingback() {
252  if ( !$this->acquireLock() ) {
253  $this->logger->debug( __METHOD__ . ": couldn't acquire lock" );
254  return false;
255  }
256 
257  $data = $this->getData();
258  if ( !$this->postPingback( $data ) ) {
259  $this->logger->warning( __METHOD__ . ": failed to send pingback; check 'http' log" );
260  return false;
261  }
262 
263  $this->markSent();
264  $this->logger->debug( __METHOD__ . ": pingback sent OK ({$this->key})" );
265  return true;
266  }
267 
272  public static function schedulePingback() {
274  $instance = new Pingback;
275  if ( $instance->shouldSend() ) {
276  $instance->sendPingback();
277  }
278  } );
279  }
280 }
Pingback\$logger
LoggerInterface $logger
Definition: Pingback.php:34
ObjectCache\getLocalClusterInstance
static getLocalClusterInstance()
Get the main cluster-local cache object.
Definition: ObjectCache.php:342
Pingback\getSystemInfo
getSystemInfo()
Collect basic data about this MediaWiki installation and return it as an associative array conforming...
Definition: Pingback.php:143
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
Pingback\$config
Config $config
Definition: Pingback.php:45
Pingback\checkIfSent
checkIfSent()
Has a pingback been sent in the last month for this MediaWiki version?
Definition: Pingback.php:75
$dbr
$dbr
Definition: testCompression.php:50
Config
Interface for configuration instances.
Definition: Config.php:28
Pingback\sendPingback
sendPingback()
Send information about this MediaWiki instance to MediaWiki.org.
Definition: Pingback.php:251
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:115
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
Pingback
Send information about this MediaWiki instance to MediaWiki.org.
Definition: Pingback.php:32
Pingback\$id
string $id
Randomly-generated identifier for this wiki.
Definition: Pingback.php:51
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2575
Pingback\acquireLock
acquireLock()
Acquire lock for sending a pingback.
Definition: Pingback.php:117
Pingback\markSent
markSent()
Record the fact that we have sent a pingback for this MediaWiki version, to ensure we don't submit da...
Definition: Pingback.php:97
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
Pingback\shouldSend
shouldSend()
Should a pingback be sent?
Definition: Pingback.php:67
DB_MASTER
const DB_MASTER
Definition: defines.php:26
Pingback\getData
getData()
Get the EventLogging packet to be sent to the server.
Definition: Pingback.php:170
Pingback\__construct
__construct(Config $config=null, LoggerInterface $logger=null)
Definition: Pingback.php:57
MWCryptRand\generateHex
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
Definition: MWCryptRand.php:36
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:431
Pingback\$key
string $key
updatelog key (also used as cache/db lock key)
Definition: Pingback.php:48
$cache
$cache
Definition: mcc.php:33
Pingback\postPingback
postPingback(array $data)
Serialize pingback data and send it to MediaWiki.org via a POST to its event beacon endpoint.
Definition: Pingback.php:229
Pingback\schedulePingback
static schedulePingback()
Schedule a deferred callable that will check if a pingback should be sent and (if so) proceed to send...
Definition: Pingback.php:272
Pingback\getOrCreatePingbackId
getOrCreatePingbackId()
Get a unique, stable identifier for this wiki.
Definition: Pingback.php:187
DeferredUpdates\addCallableUpdate
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add a callable update.
Definition: DeferredUpdates.php:124