APCBagOStuff.php 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. /**
  3. * Object caching using PHP's APC accelerator.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. * @file
  21. * @ingroup Cache
  22. */
  23. /**
  24. * This is a wrapper for APC's shared memory functions
  25. *
  26. * Use PHP serialization to avoid bugs and easily create CAS tokens.
  27. * APCu has a memory corruption bug when the serializer is set to 'default'.
  28. * See T120267, and upstream bug reports:
  29. * - https://github.com/krakjoe/apcu/issues/38
  30. * - https://github.com/krakjoe/apcu/issues/35
  31. * - https://github.com/krakjoe/apcu/issues/111
  32. *
  33. * @ingroup Cache
  34. */
  35. class APCBagOStuff extends MediumSpecificBagOStuff {
  36. /** @var bool Whether to trust the APC implementation to serialization */
  37. private $nativeSerialize;
  38. /**
  39. * @var string String to append to each APC key. This may be changed
  40. * whenever the handling of values is changed, to prevent existing code
  41. * from encountering older values which it cannot handle.
  42. */
  43. const KEY_SUFFIX = ':4';
  44. public function __construct( array $params = [] ) {
  45. $params['segmentationSize'] = $params['segmentationSize'] ?? INF;
  46. parent::__construct( $params );
  47. // The extension serializer is still buggy, unlike "php" and "igbinary"
  48. $this->nativeSerialize = ( ini_get( 'apc.serializer' ) !== 'default' );
  49. }
  50. protected function doGet( $key, $flags = 0, &$casToken = null ) {
  51. $casToken = null;
  52. $blob = apc_fetch( $key . self::KEY_SUFFIX );
  53. $value = $this->nativeSerialize ? $blob : $this->unserialize( $blob );
  54. if ( $value !== false ) {
  55. $casToken = $blob; // don't bother hashing this
  56. }
  57. return $value;
  58. }
  59. protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
  60. apc_store(
  61. $key . self::KEY_SUFFIX,
  62. $this->nativeSerialize ? $value : $this->serialize( $value ),
  63. $exptime
  64. );
  65. return true;
  66. }
  67. protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
  68. return apc_add(
  69. $key . self::KEY_SUFFIX,
  70. $this->nativeSerialize ? $value : $this->serialize( $value ),
  71. $exptime
  72. );
  73. }
  74. protected function doDelete( $key, $flags = 0 ) {
  75. apc_delete( $key . self::KEY_SUFFIX );
  76. return true;
  77. }
  78. public function incr( $key, $value = 1, $flags = 0 ) {
  79. return apc_inc( $key . self::KEY_SUFFIX, $value );
  80. }
  81. public function decr( $key, $value = 1, $flags = 0 ) {
  82. return apc_dec( $key . self::KEY_SUFFIX, $value );
  83. }
  84. }