/includes/qcodo/_core/qform_state_handlers/QFileFormStateHandler.class.php

https://github.com/quinta/qcodo · PHP · 168 lines · 69 code · 21 blank · 78 comment · 17 complexity · 507f0b7bd62be88a27fff555dd6035fc MD5 · raw file

  1. <?php
  2. /**
  3. * This will store the formstate in a pre-specified directory on the file system.
  4. * This offers significant speed advantage over PHP SESSION because EACH form state
  5. * is saved in its own file, and only the form state that is needed for loading will
  6. * be accessed (as opposed to with session, ALL the form states are loaded into memory
  7. * every time).
  8. *
  9. * The downside is that because it doesn't utilize PHP's session management subsystem,
  10. * this class must take care of its own garbage collection/deleting of old/outdated
  11. * formstate files.
  12. *
  13. * Because the index is randomy generated and MD5-hashed, there is no benefit from
  14. * encrypting it -- therefore, the QForm encryption preferences are ignored when using
  15. * QFileFormStateHandler.
  16. */
  17. class QFileFormStateHandler extends QBaseClass {
  18. /**
  19. * The PATH where the FormState files should be saved
  20. *
  21. * @var string StatePath
  22. */
  23. public static $StatePath = '/tmp';
  24. /**
  25. * The filename prefix to be used by all FormState files
  26. *
  27. * @var string FileNamePrefix
  28. */
  29. public static $FileNamePrefix = 'qformstate_';
  30. /**
  31. * The interval of hits before the garbage collection should kick in to delete
  32. * old FormState files, or 0 if it should never be run. The higher the number,
  33. * the less often it runs (better aggregated-average performance, but requires more
  34. * hard drive space). The lower the number, the more often it runs (slower aggregated-average
  35. * performance, but requires less hard drive space).
  36. *
  37. * @var integer GarbageCollectInterval
  38. */
  39. public static $GarbageCollectInterval = 200;
  40. /**
  41. * The minimum age (in days) a formstate file has to be in order to be considered old enough
  42. * to be garbage collected. So if set to "1.5", then all formstate files older than 1.5 days
  43. * will be deleted when the GC interval is kicked off.
  44. *
  45. * Obviously, if the GC Interval is set to 0, then this GC Days Old value will be never used.
  46. *
  47. * @var integer GarbageCollectDaysOld
  48. */
  49. public static $GarbageCollectDaysOld = 2;
  50. /**
  51. * If PHP SESSION is enabled, then this method will delete all formstate files specifically
  52. * for this SESSION user (and no one else). This can be used in lieu of or in addition to the
  53. * standard interval-based garbage collection mechanism.
  54. *
  55. * Also, for standard web applications with logins, it might be a good idea to call
  56. * this method whenever the user logs out.
  57. */
  58. public static function DeleteFormStateForSession() {
  59. // Figure Out Session Id (if applicable)
  60. $strSessionId = session_id();
  61. $strPrefix = self::$FileNamePrefix . $strSessionId;
  62. // Go through all the files
  63. if (strlen($strSessionId)) {
  64. $objDirectory = dir(self::$StatePath);
  65. while (($strFile = $objDirectory->read()) !== false) {
  66. $intPosition = strpos($strFile, $strPrefix);
  67. if (($intPosition !== false) && ($intPosition == 0))
  68. unlink(sprintf('%s/%s', self::$StatePath, $strFile));
  69. }
  70. }
  71. }
  72. /**
  73. * This will delete all the formstate files that are older than $GarbageCollectDaysOld
  74. * days old.
  75. */
  76. public static function GarbageCollect() {
  77. // Go through all the files
  78. $objDirectory = dir(self::$StatePath);
  79. while (($strFile = $objDirectory->read()) !== false) {
  80. if (!count(self::$FileNamePrefix))
  81. $intPosition = 0;
  82. else
  83. $intPosition = strpos($strFile, self::$FileNamePrefix);
  84. if (($intPosition !== false) && ($intPosition == 0)) {
  85. $strFile = sprintf('%s/%s', self::$StatePath, $strFile);
  86. $intTimeInterval = time() - (60 * 60 * 24 * self::$GarbageCollectDaysOld);
  87. $intModifiedTime = filemtime($strFile);
  88. if ($intModifiedTime < $intTimeInterval)
  89. unlink($strFile);
  90. }
  91. }
  92. }
  93. public static function Save($strFormState, $blnBackButtonFlag) {
  94. // First see if we need to perform garbage collection
  95. if (self::$GarbageCollectInterval > 0) {
  96. // This is a crude interval-tester, but it works
  97. if (rand(1, self::$GarbageCollectInterval) == 1)
  98. self::GarbageCollect();
  99. }
  100. // Compress (if available)
  101. if (function_exists('gzcompress'))
  102. $strFormState = gzcompress($strFormState, 9);
  103. // Figure Out Session Id (if applicable)
  104. $strSessionId = session_id();
  105. // Calculate a new unique Page Id
  106. $strPageId = md5(microtime());
  107. // Figure Out FilePath
  108. $strFilePath = sprintf('%s/%s%s_%s',
  109. self::$StatePath,
  110. self::$FileNamePrefix,
  111. $strSessionId,
  112. $strPageId);
  113. // Save THIS formstate to the file system
  114. // NOTE: if gzcompress is used, we are saving the *BINARY* data stream of the compressed formstate
  115. // In theory, this SHOULD work. But if there is a webserver/os/php version that doesn't like
  116. // binary session streams, you can first base64_encode before saving to session (see note below).
  117. file_put_contents($strFilePath, $strFormState);
  118. // Return the Page Id
  119. // Because of the MD5-random nature of the Page ID, there is no need/reason to encrypt it
  120. return $strPageId;
  121. }
  122. public static function Load($strPostDataState) {
  123. // Pull Out strPageId
  124. $strPageId = $strPostDataState;
  125. // Figure Out Session Id (if applicable)
  126. $strSessionId = session_id();
  127. // Figure Out FilePath
  128. $strFilePath = sprintf('%s/%s%s_%s',
  129. self::$StatePath,
  130. self::$FileNamePrefix,
  131. $strSessionId,
  132. $strPageId);
  133. if (file_exists($strFilePath)) {
  134. // Pull FormState from file system
  135. // NOTE: if gzcompress is used, we are restoring the *BINARY* data stream of the compressed formstate
  136. // In theory, this SHOULD work. But if there is a webserver/os/php version that doesn't like
  137. // binary session streams, you can first base64_decode before restoring from session (see note above).
  138. $strSerializedForm = file_get_contents($strFilePath);
  139. // Uncompress (if available)
  140. if (function_exists('gzcompress'))
  141. $strSerializedForm = gzuncompress($strSerializedForm);
  142. return $strSerializedForm;
  143. } else
  144. return null;
  145. }
  146. }
  147. ?>