@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix a PHP 8.1 strlen() issue with "mysql.pass" configuration

Summary:
Ref T13588. This configuration value may not be set.

Also fix an issue in `bin/storage` and whatever else I hit between now and this diff actually uploading.

Also fix a MySQLi report mode difference, beginning in PHP 8.1.

Also update a bunch of "static" property usage in Lisk.

Test Plan: Ran `bin/files ...` locally under PHP 8.1.

Maniphest Tasks: T13588

Differential Revision: https://secure.phabricator.com/D21744

+81 -60
+2 -1
.arclint
··· 79 79 "xhpast": { 80 80 "type": "xhpast", 81 81 "include": "(\\.php$)", 82 - "standard": "phutil.xhpast" 82 + "standard": "phutil.xhpast", 83 + "xhpast.php-version": "5.5" 83 84 } 84 85 } 85 86 }
+1 -1
scripts/sql/manage_storage.php
··· 95 95 96 96 $host = $args->getArg('host'); 97 97 $ref_key = $args->getArg('ref'); 98 - if (strlen($host) || strlen($ref_key)) { 98 + if (($host !== null) || ($ref_key !== null)) { 99 99 if ($host && $ref_key) { 100 100 throw new PhutilArgumentUsageException( 101 101 pht(
+1
src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php
··· 26 26 27 27 public function canWriteFiles() { 28 28 $path = PhabricatorEnv::getEnvConfig('storage.local-disk.path'); 29 + $path = phutil_string_cast($path); 29 30 return (bool)strlen($path); 30 31 } 31 32
+1 -1
src/applications/meta/query/PhabricatorApplicationQuery.php
··· 89 89 } 90 90 } 91 91 92 - if (strlen($this->nameContains)) { 92 + if ($this->nameContains !== null) { 93 93 foreach ($apps as $key => $app) { 94 94 if (stripos($app->getName(), $this->nameContains) === false) { 95 95 unset($apps[$key]);
+1 -1
src/applications/people/query/PhabricatorPeopleQuery.php
··· 341 341 (int)$this->isMailingList); 342 342 } 343 343 344 - if (strlen($this->nameLike)) { 344 + if ($this->nameLike !== null) { 345 345 $where[] = qsprintf( 346 346 $conn, 347 347 'user.username LIKE %~ OR user.realname LIKE %~',
+2 -1
src/applications/people/storage/PhabricatorUser.php
··· 275 275 $this->setConduitCertificate($this->generateConduitCertificate()); 276 276 } 277 277 278 - if (!strlen($this->getAccountSecret())) { 278 + $secret = $this->getAccountSecret(); 279 + if (($secret === null) || !strlen($secret)) { 279 280 $this->setAccountSecret(Filesystem::readRandomCharacters(64)); 280 281 } 281 282
+10
src/applications/phid/handle/pool/PhabricatorHandleList.php
··· 126 126 /* -( Iterator )----------------------------------------------------------- */ 127 127 128 128 129 + #[\ReturnTypeWillChange] 129 130 public function rewind() { 130 131 $this->cursor = 0; 131 132 } 132 133 134 + #[\ReturnTypeWillChange] 133 135 public function current() { 134 136 return $this->getHandle($this->phids[$this->cursor]); 135 137 } 136 138 139 + #[\ReturnTypeWillChange] 137 140 public function key() { 138 141 return $this->phids[$this->cursor]; 139 142 } 140 143 144 + #[\ReturnTypeWillChange] 141 145 public function next() { 142 146 ++$this->cursor; 143 147 } 144 148 149 + #[\ReturnTypeWillChange] 145 150 public function valid() { 146 151 return ($this->cursor < $this->count); 147 152 } ··· 150 155 /* -( ArrayAccess )-------------------------------------------------------- */ 151 156 152 157 158 + #[\ReturnTypeWillChange] 153 159 public function offsetExists($offset) { 154 160 // NOTE: We're intentionally not loading handles here so that isset() 155 161 // checks do not trigger fetches. This gives us better bulk loading ··· 162 168 return isset($this->map[$offset]); 163 169 } 164 170 171 + #[\ReturnTypeWillChange] 165 172 public function offsetGet($offset) { 166 173 if ($this->handles === null) { 167 174 $this->loadHandles(); ··· 169 176 return $this->handles[$offset]; 170 177 } 171 178 179 + #[\ReturnTypeWillChange] 172 180 public function offsetSet($offset, $value) { 173 181 $this->raiseImmutableException(); 174 182 } 175 183 184 + #[\ReturnTypeWillChange] 176 185 public function offsetUnset($offset) { 177 186 $this->raiseImmutableException(); 178 187 } ··· 189 198 /* -( Countable )---------------------------------------------------------- */ 190 199 191 200 201 + #[\ReturnTypeWillChange] 192 202 public function count() { 193 203 return $this->count; 194 204 }
+1
src/infrastructure/cluster/PhabricatorDatabaseRef.php
··· 322 322 $default_user = PhabricatorEnv::getEnvConfig('mysql.user'); 323 323 324 324 $default_pass = PhabricatorEnv::getEnvConfig('mysql.pass'); 325 + $default_pass = phutil_string_cast($default_pass); 325 326 $default_pass = new PhutilOpaqueEnvelope($default_pass); 326 327 327 328 $config = PhabricatorEnv::getEnvConfig('cluster.databases');
+1 -1
src/infrastructure/query/PhabricatorQuery.php
··· 87 87 foreach ($this->flattenSubclause($part) as $subpart) { 88 88 $result[] = $subpart; 89 89 } 90 - } else if (strlen($part)) { 90 + } else if (($part !== null) && strlen($part)) { 91 91 $result[] = $part; 92 92 } 93 93 }
+7
src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php
··· 57 57 } 58 58 } 59 59 60 + // See T13588. In PHP 8.1, the default "report mode" for MySQLi has 61 + // changed, which causes MySQLi to raise exceptions. Disable exceptions 62 + // to align behavior with older default behavior under MySQLi, which 63 + // this code expects. Plausibly, this code could be updated to use 64 + // MySQLi exceptions to handle errors under a wider range of PHP versions. 65 + mysqli_report(MYSQLI_REPORT_OFF); 66 + 60 67 $conn = mysqli_init(); 61 68 62 69 $timeout = $this->getConfiguration('timeout');
+52 -52
src/infrastructure/storage/lisk/LiskDAO.php
··· 193 193 194 194 private static $connections = array(); 195 195 196 + private static $liskMetadata = array(); 197 + 196 198 protected $id; 197 199 protected $phid; 198 200 protected $dateCreated; ··· 403 405 * @task config 404 406 */ 405 407 public function getConfigOption($option_name) { 406 - static $options = null; 408 + $options = $this->getLiskMetadata('config'); 407 409 408 - if (!isset($options)) { 410 + if ($options === null) { 409 411 $options = $this->getConfiguration(); 412 + $this->setLiskMetadata('config', $options); 410 413 } 411 414 412 415 return idx($options, $option_name); ··· 439 442 440 443 return $this->loadOneWhere( 441 444 '%C = %d', 442 - $this->getIDKeyForUse(), 445 + $this->getIDKey(), 443 446 $id); 444 447 } 445 448 ··· 554 557 555 558 $result = $this->loadOneWhere( 556 559 '%C = %d', 557 - $this->getIDKeyForUse(), 560 + $this->getIDKey(), 558 561 $this->getID()); 559 562 560 563 if (!$result) { ··· 579 582 * @task load 580 583 */ 581 584 public function loadFromArray(array $row) { 582 - static $valid_properties = array(); 585 + $valid_map = $this->getLiskMetadata('validMap', array()); 583 586 584 587 $map = array(); 588 + $updated = false; 585 589 foreach ($row as $k => $v) { 586 590 // We permit (but ignore) extra properties in the array because a 587 591 // common approach to building the array is to issue a raw SELECT query ··· 594 598 // path (assigning an invalid property which we've already seen) costs 595 599 // an empty() plus an isset(). 596 600 597 - if (empty($valid_properties[$k])) { 598 - if (isset($valid_properties[$k])) { 601 + if (empty($valid_map[$k])) { 602 + if (isset($valid_map[$k])) { 599 603 // The value is set but empty, which means it's false, so we've 600 604 // already determined it's not valid. We don't need to check again. 601 605 continue; 602 606 } 603 - $valid_properties[$k] = $this->hasProperty($k); 604 - if (!$valid_properties[$k]) { 607 + $valid_map[$k] = $this->hasProperty($k); 608 + $updated = true; 609 + if (!$valid_map[$k]) { 605 610 continue; 606 611 } 607 612 } ··· 609 614 $map[$k] = $v; 610 615 } 611 616 617 + if ($updated) { 618 + $this->setLiskMetadata('validMap', $valid_map); 619 + } 620 + 612 621 $this->willReadData($map); 613 622 614 623 foreach ($map as $prop => $value) { ··· 686 695 * @task save 687 696 */ 688 697 public function setID($id) { 689 - static $id_key = null; 690 - if ($id_key === null) { 691 - $id_key = $this->getIDKeyForUse(); 692 - } 698 + $id_key = $this->getIDKey(); 693 699 $this->$id_key = $id; 694 700 return $this; 695 701 } ··· 704 710 * @task info 705 711 */ 706 712 public function getID() { 707 - static $id_key = null; 708 - if ($id_key === null) { 709 - $id_key = $this->getIDKeyForUse(); 710 - } 713 + $id_key = $this->getIDKey(); 711 714 return $this->$id_key; 712 715 } 713 716 ··· 742 745 * @task info 743 746 */ 744 747 protected function getAllLiskProperties() { 745 - static $properties = null; 746 - if (!isset($properties)) { 747 - $class = new ReflectionClass(get_class($this)); 748 + $properties = $this->getLiskMetadata('properties'); 749 + 750 + if ($properties === null) { 751 + $class = new ReflectionClass(static::class); 748 752 $properties = array(); 749 753 foreach ($class->getProperties(ReflectionProperty::IS_PROTECTED) as $p) { 750 754 $properties[strtolower($p->getName())] = $p->getName(); ··· 763 767 if ($id_key != 'phid' && !$this->getConfigOption(self::CONFIG_AUX_PHID)) { 764 768 unset($properties['phid']); 765 769 } 770 + 771 + $this->setLiskMetadata('properties', $properties); 766 772 } 773 + 767 774 return $properties; 768 775 } 769 776 ··· 777 784 * @task info 778 785 */ 779 786 protected function checkProperty($property) { 780 - static $properties = null; 781 - if ($properties === null) { 782 - $properties = $this->getAllLiskProperties(); 783 - } 787 + $properties = $this->getAllLiskProperties(); 784 788 785 789 $property = strtolower($property); 786 790 if (empty($properties[$property])) { ··· 996 1000 'UPDATE %R SET %LQ WHERE %C = '.(is_int($id) ? '%d' : '%s'), 997 1001 $this, 998 1002 $map, 999 - $this->getIDKeyForUse(), 1003 + $this->getIDKey(), 1000 1004 $id); 1001 1005 // We can't detect a missing object because updating an object without 1002 1006 // changing any values doesn't affect rows. We could jiggle timestamps ··· 1023 1027 $conn->query( 1024 1028 'DELETE FROM %R WHERE %C = %d', 1025 1029 $this, 1026 - $this->getIDKeyForUse(), 1030 + $this->getIDKey(), 1027 1031 $this->getID()); 1028 1032 1029 1033 $this->didDelete(); ··· 1051 1055 // If we are using autoincrement IDs, let MySQL assign the value for the 1052 1056 // ID column, if it is empty. If the caller has explicitly provided a 1053 1057 // value, use it. 1054 - $id_key = $this->getIDKeyForUse(); 1058 + $id_key = $this->getIDKey(); 1055 1059 if (empty($data[$id_key])) { 1056 1060 unset($data[$id_key]); 1057 1061 } ··· 1059 1063 case self::IDS_COUNTER: 1060 1064 // If we are using counter IDs, assign a new ID if we don't already have 1061 1065 // one. 1062 - $id_key = $this->getIDKeyForUse(); 1066 + $id_key = $this->getIDKey(); 1063 1067 if (empty($data[$id_key])) { 1064 1068 $counter_name = $this->getTableName(); 1065 1069 $id = self::loadNextCounterValue($conn, $counter_name); ··· 1174 1178 public function getIDKey() { 1175 1179 return 'id'; 1176 1180 } 1177 - 1178 - 1179 - protected function getIDKeyForUse() { 1180 - $id_key = $this->getIDKey(); 1181 - if (!$id_key) { 1182 - throw new Exception( 1183 - pht( 1184 - 'This DAO does not have a single-part primary key. The method you '. 1185 - 'called requires a single-part primary key.')); 1186 - } 1187 - return $id_key; 1188 - } 1189 - 1190 1181 1191 1182 /** 1192 1183 * Generate a new PHID, used by CONFIG_AUX_PHID. ··· 1592 1583 * @task util 1593 1584 */ 1594 1585 public function __call($method, $args) { 1595 - // NOTE: PHP has a bug that static variables defined in __call() are shared 1596 - // across all children classes. Call a different method to work around this 1597 - // bug. 1598 - return $this->call($method, $args); 1599 - } 1586 + $dispatch_map = $this->getLiskMetadata('dispatchMap', array()); 1600 1587 1601 - /** 1602 - * @task util 1603 - */ 1604 - final protected function call($method, $args) { 1605 1588 // NOTE: This method is very performance-sensitive (many thousands of calls 1606 1589 // per page on some pages), and thus has some silliness in the name of 1607 1590 // optimizations. 1608 1591 1609 - static $dispatch_map = array(); 1610 - 1611 1592 if ($method[0] === 'g') { 1612 1593 if (isset($dispatch_map[$method])) { 1613 1594 $property = $dispatch_map[$method]; ··· 1620 1601 throw new Exception(pht('Bad getter call: %s', $method)); 1621 1602 } 1622 1603 $dispatch_map[$method] = $property; 1604 + $this->setLiskMetadata('dispatchMap', $dispatch_map); 1623 1605 } 1624 1606 1625 1607 return $this->readField($property); ··· 1632 1614 if (substr($method, 0, 3) !== 'set') { 1633 1615 throw new Exception(pht("Unable to resolve method '%s'!", $method)); 1634 1616 } 1617 + 1635 1618 $property = substr($method, 3); 1636 1619 $property = $this->checkProperty($property); 1637 1620 if (!$property) { 1638 1621 throw new Exception(pht('Bad setter call: %s', $method)); 1639 1622 } 1640 1623 $dispatch_map[$method] = $property; 1624 + $this->setLiskMetadata('dispatchMap', $dispatch_map); 1641 1625 } 1642 1626 1643 1627 $this->writeField($property, $args[0]); ··· 1908 1892 return $this->getTableName(); 1909 1893 } 1910 1894 1895 + 1896 + private function getLiskMetadata($key, $default = null) { 1897 + if (isset(self::$liskMetadata[static::class][$key])) { 1898 + return self::$liskMetadata[static::class][$key]; 1899 + } 1900 + 1901 + if (!isset(self::$liskMetadata[static::class])) { 1902 + self::$liskMetadata[static::class] = array(); 1903 + } 1904 + 1905 + return idx(self::$liskMetadata[static::class], $key, $default); 1906 + } 1907 + 1908 + private function setLiskMetadata($key, $value) { 1909 + self::$liskMetadata[static::class][$key] = $value; 1910 + } 1911 1911 1912 1912 }
+1 -1
src/infrastructure/util/PhabricatorHash.php
··· 224 224 $cache_key = "hmac.key({$hmac_name})"; 225 225 226 226 $hmac_key = $cache->getKey($cache_key); 227 - if (!strlen($hmac_key)) { 227 + if (($hmac_key === null) || !strlen($hmac_key)) { 228 228 $hmac_key = self::readHMACKey($hmac_name); 229 229 230 230 if ($hmac_key === null) {
+1 -1
src/infrastructure/util/PhabricatorMetronome.php
··· 49 49 } 50 50 51 51 public function setOffsetFromSeed($seed) { 52 - $offset = PhabricatorHash::digestToRange($seed, 0, PHP_INT_MAX); 52 + $offset = PhabricatorHash::digestToRange($seed, 0, 0x7FFFFFFF); 53 53 return $this->setOffset($offset); 54 54 } 55 55