• Content Count

  • Joined

  • Last visited

Community Reputation

36 Excellent

1 Follower

About ren

  • Rank
    Jr. Member

Contact Methods

  • Website URL

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Opened an issue
  2. Upgraded a site from 3.0.98 to 3.0.123 and now all admin pages are timing out. The problem seems to be debug mode in combination with using WireCache for around 3,400 items. Confirmed on a fresh install, but would appreciate if anyone could try replicating before I file an issue... To replicate, in config.php: $config->debug = true; $config->debugTools = array( 'pages', 'api', 'session', 'modules', 'hooks', 'database', 'db', 'timers', 'user', 'input', 'cache', ); Fill the cache with some dummy data: for ($i = 1; $i < 4000; $i++) { $cache->save($i, $i); } Then try and view any admin page. The issue goes away if 'cache' is removed from $config->debugTools , or if the site is downgraded to 3.0.98. Happens with or without Tracy.
  3. The header and footer are looking lovely with the original logo. Just noticed that the home page section title "ProcessWire News & Community" is replaced once the content is pulled in (LInux Firefox & Chrome).
  4. LInux Chrome (Firefox is the same) (Arial)
  5. There is already some information on how to do this but it's a bit scattered, so here's a quick tutorial... This is how $session->CSRF->hasValidToken() handles AJAX requests, by getting the token name and value from request headers: if($this->config->ajax && isset($_SERVER["HTTP_X_$tokenName"]) && $_SERVER["HTTP_X_$tokenName"] === $tokenValue) { $valid = true; } else if($this->input->post($tokenName) === $tokenValue) { $valid = true; } So all we need to do is to pass the name and value to our JavaScript and set the right headers with our AJAX request. We could instead of setting headers put the name and value pair into the body of a POST request, as the second conditional doesn't care if the POST request is received via AJAX or not. But this limits the request to POST and the body data type to either multipart/form-data or application/x-www-form-urlencoded (because that's all that PHP's $_POST superglobal will handle). Admittedly this might be 99% of use cases, but for example if a GET request invokes significant processing then CSRF protection could be used to prevent a DOS attack on the endpoint. So, for the sake of a bit more flexibility, and to be more in keeping with what PW expects, we'll use request headers. I find it neater to write the token name and value into HTML and retrieve that using JavaScript DOM functions, instead of writing JavaScript with PHP . So somewhere, maybe in, get the token name and value: $csrfTokenName = $session->CSRF->getTokenName(); $csrfTokenValue = $session->CSRF->getTokenValue(); Then in a global footer template: <div class="js-csrf-token" style="display:none;" data-csrf-token-name="<?php echo $csrfTokenName; ?>" data-csrf-token-value="<?php echo $csrfTokenValue; ?>"></div> Now to retrieve the token in JavaScript: function getCsrfToken() { const csrfTokenNode = document.getElementsByClassName('js-csrf-token')[0]; return { name: csrfTokenNode.getAttribute('data-csrf-token-name'), value: csrfTokenNode.getAttribute('data-csrf-token-value'), } } Then in any AJAX request: const csrfToken = getCsrfToken(); let xhr = new XMLHttpRequest(); // ... // open the request and do some configuration // ... xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // tell the server and PW that it's an AJAX request xhr.setRequestHeader('X-' +, csrfToken.value); // create a header with the token // ... // send the request // ... And that's all, in the endpoint just do... if ($session->CSRF->hasValidToken()) { // works for AJAX! } This has used the default CSRF token created for every session, but to create and use a different token just specify an id: $csrfTokenName = $session->CSRF->getTokenName('myAjaxToken'); // this creates a token if one with the given id doesn't exist $csrfTokenValue = $session->CSRF->getTokenValue('myAjaxToken'); and... if ($session->CSRF->hasValidToken('myAjaxToken') { // ... }
  6. ren

    Ooh, that sounds cool! Yeah, that makes sense. Forgot about that lovely new addition! Looking forward to not writing my own functions Agreed that there's no harm in guarding against any potential changes. AH! Right, so in the example code, $form->processInput applies the Inputfield sanitizers but $pages->add does not? Thanks for the wide-ranging examples!
  7. If I were explaining why I love PW to another developer I'd say... Unopinionated Powerful stable API Security Extremely active, friendly, *knowledgeable* community. I feel like that covers the major pain points that CMS/CMF developers feel, particularly 1) and 2). PW has so many great points that it's tempting to want to cover them all. I kinda agree with others that maybe there are too many points, and too much content.
  8. Seconded. I find the body text on blue background slightly hard to read.
  9. The search box doesn't close when losing focus, and tab doesn't shift focus to the other menu items. (Linux Chrome 68.0.3440.75)
  10. Love it! The only thing I'm not sure about is the emphasis on... I feel that a low maintenance overhead is already strongly implied by reliability and security sections. I like to run updates if only to keep the CK Editor plugin up-to-date, which *does* have semi-regular security patches. It might not appeal to developers for whom updates are bread and butter. I'd rather see something like... Lower maintenance costs, because security, reliability, and a stable API resulting in painless upgrades. Yeah, I once did a major version PW upgrade on a fairly complex 30,000+ page site and *nothing* broke! Zero. Zilch. Nada. It brought tears to my eyes. A lack of breakage that is unheard of in CMS land. Compare with regular minor version breakage for some other CMS
  11. Hi, This is kind of an open ended question, but I find I'm not using $santizer much because the PW API takes care of most sanitization, and I'm wondering if this is actually ok. Take for example a contact form which creates a page for each message and emails admin. Something like this... Edit: this is incorrect // The page's Inputfields run the same sanitizers as processInput() above // Optionally with stripTags enabled See the reply from @teppo $form = $modules->get('InputfieldForm'); $form->action = $page->url; $fullNameField = $modules->get('InputfieldText'); $fullNameField->name = 'fullName'; $fullNameField->required = 1; $emailField = $modules->get('InputfieldEmail'); $emailField->name = 'email'; $emailField->required = 1; $messageField = $modules->get('InputfieldTextarea'); $messageField->name = 'message'; $messageField->required = 1; $form->append($nameField); $form->append($emailField); $form->append($messageField); $csrfTokenName = $session->CSRF->getTokenName(); $csrfTokenValue = $session->CSRF->getTokenValue(); $fullNameMarkup = ''; $emailMarkup = ''; $messageMarkup = ''; if ($input->post->submit) { // processInput assigns $input values to the form Inputfields by calling each Inputfields' setAttribute() method // setAttribute() calls setAttributeValue() which does sanitization, e.g. // InputfieldText runs $sanitizer->text with stripTags set to false by default // InputfieldTextarea runs $sanitizer->textarea with stripTags set to false by default // InputfieldEmail runs $sanitizer->email $form->processInput($input->post); // Output needs to be entity encoded $fullNameMarkup = $sanitizer->entities($form->fullName->value); $emailMarkup = $sanitizer->entities($form->email->value); $messageMarkup = $sanitizer->entities(nl2br($form->message->value)); if (!$form->getErrors()) { $adminEmail = sendEmailToAdmin($fullNameMarkup, $emailMarkup, $messageMarkup); if (!$adminEmail) { return wireRenderFile($config->paths->templates . 'includes/contact/', [ 'type' => 'send email' ]); } try { $createPage = $pages->add('contact', '/contacts/', [ // The page's Inputfields run the same sanitizers as processInput() above // Optionally with stripTags enabled 'contact_full_name' => $form->fullName->value, 'contact_email' => $form->email->value, 'contact_message' => $form->message->value, ]); } catch (WireException $e) { return wireRenderFile($config->paths->templates . 'includes/contact/', [ 'type' => 'create page', 'error' => $e ]); } return wireRenderFile($config->paths->templates . 'includes/contact/' } } return wireRenderFile($config->paths->templates . 'includes/contact/', [ 'fullNameMarkup' => $fullNameMarkup, 'emailMarkup' => $emailMarkup, 'messageMarkup' => $messageMarkup, 'csrfTokenName' => $csrfTokenName, 'csrfTokenValue' => $csrfTokenValue, 'errors' => $form->getErrors(), ]); So processInput() ensures the email address is valid, and all markup is entity encoded. Even stripping tags seems unnecessary since page fields always give entity encoded output unless output formatting is disabled. So I only really use $sanitizer->entities(), $sanitizer->selectorValue(), and occasionally $sanitizer->name(); Am I missing something? How do you use $sanitizer?
  12. Patch #5463406 solves both issues Thanks Ryan
  13. Thanks matjazp, I've added to the issue report.