/** * Path For Asset Url * @param string assetUrl * @return string */ public static function pathForAssetUrl($assetUrl, $assetType = null) { if (Router::isSiteUrl($assetUrl)) { list($assetMapFragment, $assetUrl) = array_pad(explode("/", Router::relativeUrl($assetUrl), 2), 2, null); $file = File::create([BASE_PATH, static::pathForAssetMap($assetMapFragment), $assetUrl]); if ($file->exists()) { return $file->path; } // //Is it a folder? // $folder = Folder::create([BASE_PATH, static::pathForAssetMap($assetMapFragment), $assetUrl]); // if($folder->exists()){ // return $folder->path; // } return null; } return $assetUrl; }
/** * Validate Html * This method scans the outgoing HTML for any forms, if found it will save the form to the session in order to validate. * If any errors previously existed in the session, this method will apply `bootstrap` style css error classes. * @pararm string &$htmlDocument - The outgoing HTML string * @return VOID */ private function validateHtml(&$htmlDocument) { if (!empty($htmlDocument)) { $dom = new DOMDocument(); $dom->loadHtml($htmlDocument, LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOENT | LIBXML_HTML_NOIMPLIED); //Automatically apply an active class to links that relate to the current URL foreach ($dom->getElementsByTagName('a') as $link) { if (Router::isSiteUrl($href = Router::relativeURL($link->getAttribute("href")))) { $currentClasses = explode(" ", $link->getAttribute("class")); if (strcasecmp($href, $this->controller->request()->url()) == 0) { $currentClasses[] = 'active'; } if (strpos($this->controller->request()->url(), $href) === 0) { $currentClasses[] = 'child-active'; } $link->setAttribute('class', implode(" ", $currentClasses)); } } //Save the outgoing form elements for future validation. foreach ($dom->getElementsByTagName('form') as $form) { $savedom = new \DOMDocument(); if ($formAction = $form->getAttribute("action") && !Router::isSiteUrl($formAction)) { continue; } //Add CSRF $rand = function_exists('random_bytes') ? random_bytes(32) : null; $rand = !$rand && function_exists('mcrypt_create_iv') ? mcrypt_create_iv(32, MCRYPT_DEV_URANDOM) : $rand; $rand = $rand ? $rand : openssl_random_pseudo_bytes(32); $csrfToken = bin2hex($rand); $formName = $form->getAttribute("name"); $formNameToken = $formName . "_" . $csrfToken; $csrf = $dom->createDocumentFragment(); $csrf->appendXML(HTML::input()->attr("type", "hidden")->attr("name", "tb_form_token")->attr("value", $formNameToken)->attr("readonly", true)); $form->insertBefore($csrf, $form->firstChild); //TODO: Should we assume the form will allways have content foreach (["input", "textarea", "select"] as $tag) { foreach ($form->getElementsByTagName($tag) as $input) { $savedom->appendChild($savedom->importNode($input->cloneNode())); //Populate form with previous data if (($newValue = SessionStore::get("touchbase.key.session.post")->get($input->getAttribute("name"), false)) !== false) { if (is_scalar($newValue) && $input->getAttribute("type") !== "hidden" && !$input->hasAttribute("readonly")) { $input->setAttribute('value', $newValue); } } //Populate errors if ($errorMessage = $this->controller->errors($formName)->get($input->getAttribute("name"), false)) { $currentClasses = explode(" ", $input->parentNode->getAttribute("class")); foreach (["has-feedback", "has-error"] as $class) { if (!in_array($class, $currentClasses)) { $currentClasses[] = $class; } } $input->parentNode->setAttribute('class', implode(" ", $currentClasses)); $input->setAttribute("data-error", $errorMessage); } } } SessionStore::recycle($formName, $formNameToken, base64_encode(gzdeflate($savedom->saveHTML(), 9))); } //Move body scripts to bottom $bodies = $dom->getElementsByTagName('body'); $body = $bodies->item(0); if ($body) { foreach ($body->getElementsByTagName('script') as $script) { if ($script->parentNode->nodeName === "body") { break; } $body->appendChild($dom->importNode($script)); } } //Look for the special attribute that moves nodes. //This is useful for moving modals from the template files to the bottom output. $xpath = new \DOMXPath($dom); $appendToBodyRef = NULL; foreach ($xpath->query("//*[@tb-append]") as $element) { $appendTo = $xpath->query($element->getAttribute("tb-append"))->item(0); $element->removeAttribute("tb-append"); if ($appendTo) { if ($appendTo->nodeName === "body") { //Special case to append above the included javascript files. if (!$appendToBodyRef) { $appendToBodyRef = $xpath->query('/html/body/comment()[. = " END CONTENT "][1]')->item(0); } $body->insertBefore($dom->importNode($element), $appendToBodyRef); } else { $appendTo->appendChild($dom->importNode($element)); } } } //Save the HTML with the updates. if ($this->controller->request()->isAjax() || !$this->controller->request()->isMainRequest()) { //This will remove the doctype that's automatically appended. $htmlDocument = $dom->saveHTML($dom->documentElement); } else { $htmlDocument = $dom->saveHTML(); } } }