sunnysideup /
silverstripe-menucache
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | class MenuCache extends DataExtension |
||
| 4 | { |
||
| 5 | /** |
||
| 6 | * fields are typicall header, menu, footer |
||
| 7 | */ |
||
| 8 | |||
| 9 | private static $db = array( |
||
| 10 | "CachedSection0" => "HTMLText", |
||
| 11 | "CachedSection1" => "HTMLText", |
||
| 12 | "CachedSection2" => "HTMLText", |
||
| 13 | "CachedSection3" => "HTMLText", |
||
| 14 | "CachedSection4" => "HTMLText" |
||
| 15 | ); |
||
| 16 | |||
| 17 | private static $fields = array( |
||
| 18 | 0 => "Header", |
||
| 19 | 1 => "Menu", |
||
| 20 | 2 => "Footer", |
||
| 21 | 3 => "LayoutSection", |
||
| 22 | 4 => "other", |
||
| 23 | ); |
||
| 24 | |||
| 25 | /* sets the cache number used for getting the "$Layout" of the individual page */ |
||
| 26 | private static $layout_field = 3; |
||
| 27 | |||
| 28 | private static $tables_to_clear = array("SiteTree", "SiteTree_Live", "SiteTree_versions"); |
||
| 29 | |||
| 30 | public static function field_maker($fieldNumber) |
||
| 31 | { |
||
| 32 | return "CachedSection".$fieldNumber; |
||
| 33 | } |
||
| 34 | |||
| 35 | public static function fields_exists($number) |
||
| 36 | { |
||
| 37 | return (isset(self::$fields[$number])); |
||
| 38 | } |
||
| 39 | |||
| 40 | public function updateCMSFields(FieldList $fields) |
||
| 41 | { |
||
| 42 | $fields->addFieldToTab("Root.Caching", new CheckboxField("DoNotCacheMenu", "Do Not Cache Menu")); |
||
| 43 | $fields->addFieldToTab("Root.Caching", new LiteralField("ClearCache", "<a href=\"".$this->owner->Link("clearallfieldcaches")."\">clear cache (do this at the end of all edit sessions)</a>")); |
||
| 44 | return $fields; |
||
| 45 | } |
||
| 46 | |||
| 47 | //-------------------- menu cache ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ |
||
| 48 | |||
| 49 | public function clearfieldcache($showoutput = false) |
||
| 50 | { |
||
| 51 | $fieldsToClear = array(); |
||
| 52 | $fieldsForEach = Config::inst()->get("MenuCache", "fields"); |
||
| 53 | foreach ($fieldsForEach as $key => $field) { |
||
| 54 | $fieldName = self::field_maker($key); |
||
| 55 | $fieldsToClear[] = "\"".$fieldName."\" = ''"; |
||
| 56 | } |
||
| 57 | if (count($fieldsToClear)) { |
||
| 58 | $tablesForEach = Config::inst()->get("MenuCache", "tables_to_clear"); |
||
| 59 | foreach ($tablesForEach as $table) { |
||
|
0 ignored issues
–
show
|
|||
| 60 | $msg = ''; |
||
| 61 | $sql = "UPDATE \"".$table."\" SET ".implode(", ", $fieldsToClear); |
||
| 62 | if (Controller::curr()->getRequest()->param("ID") == "days" && $days = intval(Controller::curr()->getRequest()->param("OtherID"))) { |
||
| 63 | $sql .= ' WHERE \"LastEdited\" > ( NOW() - INTERVAL '.$days.' DAY )'; |
||
| 64 | $msg .= ', created before the last '.$days.' days'; |
||
| 65 | } elseif (Controller::curr()->getRequest()->param("ID") == "thispage") { |
||
| 66 | $sql .= " WHERE \"".$table."\".\"ID\" = ".$this->owner->ID; |
||
| 67 | $msg .= ', for page with ID = '.$this->owner->ID; |
||
| 68 | } |
||
| 69 | if ($showoutput) { |
||
| 70 | DB::alteration_message("Deleting cached data from $table, ".$msg); |
||
| 71 | debug::show($sql); |
||
| 72 | } |
||
| 73 | DB::query($sql); |
||
| 74 | } |
||
| 75 | } |
||
| 76 | return array(); |
||
| 77 | } |
||
| 78 | |||
| 79 | //add this function to your page class if needed |
||
| 80 | public function onBeforeWrite() |
||
| 81 | { |
||
| 82 | //$this->clearfieldcache(); // technically this should be done, but it puts a lot of strain on saving so instead we encourage people to use ?flush=1 |
||
| 83 | parent::onBeforeWrite(); |
||
| 84 | } |
||
| 85 | } |
||
| 86 | |||
| 87 | class MenuCache_Controller extends Extension |
||
| 88 | { |
||
| 89 | private static $allowed_actions = array("showcachedfield","clearfieldcache","showuncachedfield", "clearallfieldcaches"); |
||
| 90 | |||
| 91 | protected function getHtml($fieldNumber) |
||
| 92 | { |
||
| 93 | $layoutField = Config::inst()->get("MenuCache", "layout_field"); |
||
| 94 | if ($layoutField == $fieldNumber) { |
||
| 95 | $className = $this->owner->ClassName; |
||
| 96 | if ("Page" == $className) { |
||
| 97 | $className = "PageCached"; |
||
| 98 | } |
||
| 99 | return $this->owner->renderWith(array($className, "PageCached")); |
||
| 100 | } else { |
||
| 101 | return $this->owner->renderWith('UsedToCreateCache'.$fieldNumber); |
||
| 102 | } |
||
| 103 | } |
||
| 104 | |||
| 105 | public function CachedField($fieldNumber) |
||
| 106 | { |
||
| 107 | $fieldName = MenuCache::field_maker($fieldNumber); |
||
| 108 | if (isset($_REQUEST["flush"])) { |
||
| 109 | $this->owner->clearfieldcache(); |
||
| 110 | } |
||
| 111 | if (!(MenuCache::fields_exists($fieldNumber))) { |
||
| 112 | user_error("$fieldName is not a field that can be cached", E_USER_ERROR); |
||
| 113 | } else { |
||
| 114 | if (!$this->owner->$fieldName || $this->owner->DoNotCacheMenu) { |
||
| 115 | $fieldID = $fieldNumber; |
||
| 116 | $content = $this->getHtml($fieldNumber); |
||
| 117 | $sql = "Update \"SiteTree_Live\" Set \"".$fieldName."\" = '".$this->compressAndPrepareHTML($content)."' WHERE \"ID\" = ".$this->owner->ID." LIMIT 1"; |
||
| 118 | DB::query($sql); |
||
| 119 | return $content; |
||
| 120 | } else { |
||
| 121 | return $this->owner->$fieldName; |
||
| 122 | } |
||
| 123 | } |
||
| 124 | } |
||
| 125 | |||
| 126 | |||
| 127 | private function compressAndPrepareHTML($html) |
||
| 128 | { |
||
| 129 | $pat[0] = "/^\s+/"; |
||
| 130 | $pat[1] = "/\s{2,}/"; |
||
| 131 | $pat[2] = "/\s+\$/"; |
||
| 132 | $rep[0] = ""; |
||
| 133 | $rep[1] = " "; |
||
| 134 | $rep[2] = ""; |
||
| 135 | $html = preg_replace($pat, $rep, $html); |
||
| 136 | $html = trim($html); |
||
| 137 | return addslashes($html); |
||
| 138 | } |
||
| 139 | |||
| 140 | |||
| 141 | |||
| 142 | public function showcachedfield($httpRequest = null) |
||
| 143 | { |
||
| 144 | $fieldNumber = $httpRequest->param("ID"); |
||
| 145 | return $this->getHtml($fieldNumber); |
||
| 146 | } |
||
| 147 | |||
| 148 | public function showuncachedfield($httpRequest = null) |
||
| 149 | { |
||
| 150 | $this->owner->clearfieldcache(); |
||
| 151 | return $this->showcachedfield($httpRequest); |
||
| 152 | } |
||
| 153 | |||
| 154 | public function clearallfieldcaches($httpRequest = null) |
||
| 155 | { |
||
| 156 | $this->owner->clearfieldcache(true); |
||
| 157 | return 'fields have been cleared, <a href="/?flush=all">click to continue...</a>'; |
||
| 158 | } |
||
| 159 | } |
||
| 160 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.