Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
HistoryBlobStub
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 7
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setLocation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLocation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setReferrer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getReferrer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getText
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
90
 getHash
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Efficient concatenated text storage.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9// NO_NAMESPACE Compatibility with serialized objects in permanent storage
10
11use MediaWiki\MediaWikiServices;
12
13/**
14 * Pointer object for an item within a CGZ blob stored in the text table.
15 *
16 * WARNING: Objects of this class are serialized and permanently stored in the DB.
17 * Do not change the name or visibility of any property!
18 *
19 * Note: the property visibility was changed in 2020 from public to protected.
20 * This may cause problems in future.
21 */
22class HistoryBlobStub {
23    /**
24     * @var array One-step cache variable to hold base blobs; operations that
25     * pull multiple revisions may often pull multiple times from the same
26     * blob. By keeping the last-used one open, we avoid redundant
27     * unserialization and decompression overhead.
28     */
29    protected static $blobCache = [];
30
31    /** @var int */
32    protected $mOldId;
33
34    /** @var string */
35    protected $mHash;
36
37    /** @var string */
38    protected $mRef;
39
40    /**
41     * @param string $hash The content hash of the text
42     * @param int $oldid The old_id for the CGZ object
43     */
44    public function __construct( $hash = '', $oldid = 0 ) {
45        $this->mHash = $hash;
46    }
47
48    /**
49     * Sets the location (old_id) of the main object to which this object
50     * points
51     * @param int $id
52     */
53    public function setLocation( $id ) {
54        $this->mOldId = $id;
55    }
56
57    /**
58     * Gets the location of the main object
59     * @return int
60     */
61    public function getLocation() {
62        return $this->mOldId;
63    }
64
65    /**
66     * Sets the location (old_id) of the referring object
67     * @param string $id
68     */
69    public function setReferrer( $id ) {
70        $this->mRef = $id;
71    }
72
73    /**
74     * Gets the location of the referring object
75     * @return string
76     */
77    public function getReferrer() {
78        return $this->mRef;
79    }
80
81    /**
82     * @return string|false
83     */
84    public function getText() {
85        if ( isset( self::$blobCache[$this->mOldId] ) ) {
86            $obj = self::$blobCache[$this->mOldId];
87        } else {
88            $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
89            $row = $dbr->newSelectQueryBuilder()
90                ->select( [ 'old_flags', 'old_text' ] )
91                ->from( 'text' )
92                ->where( [ 'old_id' => $this->mOldId ] )
93                ->caller( __METHOD__ )->fetchRow();
94
95            if ( !$row ) {
96                return false;
97            }
98
99            $flags = explode( ',', $row->old_flags );
100            if ( in_array( 'external', $flags ) ) {
101                $url = $row->old_text;
102                $parts = explode( '://', $url, 2 );
103                if ( !isset( $parts[1] ) || $parts[1] == '' ) {
104                    return false;
105                }
106                $row->old_text = MediaWikiServices::getInstance()
107                    ->getExternalStoreAccess()
108                    ->fetchFromURL( $url );
109            }
110
111            if ( !in_array( 'object', $flags ) ) {
112                return false;
113            }
114
115            if ( in_array( 'gzip', $flags ) ) {
116                // This shouldn't happen, but a bug in the compress script
117                // may at times gzip-compress a HistoryBlob object row.
118                $obj = HistoryBlobUtils::unserialize( gzinflate( $row->old_text ), true );
119            } else {
120                $obj = HistoryBlobUtils::unserialize( $row->old_text, true );
121            }
122
123            // Save this item for reference; if pulling many
124            // items in a row we'll likely use it again.
125            self::$blobCache = [ $this->mOldId => $obj ];
126        }
127
128        if ( method_exists( $obj, 'getItem' ) ) {
129            return $obj->getItem( $this->mHash );
130        }
131
132        return false;
133    }
134
135    /**
136     * Get the content hash
137     *
138     * @return string
139     */
140    public function getHash() {
141        return $this->mHash;
142    }
143}
144
145// Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
146// class name coerced to lowercase. We can improve efficiency by adding
147// autoload entries for the lowercase variants of these classes (T166759).
148// The code below is never executed, but it is picked up by the AutoloadGenerator
149// parser, which scans for class_alias() calls.
150/*
151class_alias( HistoryBlobStub::class, 'historyblobstub' );
152*/