Jump to content
robinc

Non db dependent 'offline' page - for when pw cant reach the db

Recommended Posts

With any website, there is the possibility of db issues - overloaded server, network connectivity if the db is on another machine in the hosting network, etc.

I would love to see a feature where if there is any reason the db fails or cannot be accessed, then pw displays a dedicated page that is stored in the filesystem - instead of displaying nothing, or an ugly mysql error. Obviously it would be good to log the error, and possibly send a notification to the admin (email?).

This gives us the opportunity to still present a professional front (albeit with no functionality) while problems are resolved behind the scenes. I cannot think of a company I have worked for that hasn't had db errors at times

What are your thoughts?

  • Like 2

Share this post


Link to post
Share on other sites
34 minutes ago, robinc said:

Obviously it would be good to log the error, and possibly send a notification to the admin (email?).

Database errors are always logged. You will find entry in your /site/assets/logs/errors.txt file

2017-03-18 16:05:27    ?    http://example.org/?/    Error:     Exception: SQLSTATE[HY000] [1049] Unknown database 'example' (in .../wire/core/ProcessWire.php line 375)

Depending on your config.php settings an Email will be sent

/**
 * Admin email address
 *
 * Optional email address to send fatal error notifications to.
 *
 * #input email
 * @var string
 *
 */
$config->adminEmail = '';

In case of fatal errors the following html file will be send

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
    <title>500 Internal Server Error</title>
</head>
<body>
    <h1>Internal Server Error</h1>
    <p>The server encountered an internal error or misconfiguration and was unable to complete your request.</p>
    <p>{message}</p>
</body>
</html>

You can modify it. You'll find the file (default installation) in /site/templates/errors/500.html

  • Like 10

Share this post


Link to post
Share on other sites

Thank you :)

There is so much available in PW that sometimes one forgets it's there.

  • Like 4

Share this post


Link to post
Share on other sites

It would be nice to have an admin interface for managing this file (and linked css). Potentially with wysiwyg editing and preview function, any maybe an 'export from page' option, to create the static file.

 

Share this post


Link to post
Share on other sites

You can create a page with a ckeditor field and then hook on save to rewrite the static file. No time to give you code now.

Share this post


Link to post
Share on other sites

And here goes some code. Place this on site/ready.php (or create a module from it) and edit the first lines to your liking:

 

/*************************/
/******* EDIT HERE *******/
/*************************/

// ID of the page where the custom content is
$this->pageID = 1;

// name of the field where the custom content is
$this->fieldName = 'body';

// name of html tag and id from the parent of the custom content on the 505 file
$this->elementTag = 'div';
$this->elementID = 'message';

/*************************/
/******* END EDIT ********/
/*************************/


// regex to get the contents of parent element
$this->regex = '/(<'.$this->elementTag.'\sid=("|\')?'.$this->elementID.'("|\')?>)([^<]|<.+>.*<\/.+>)+(<\/'.$this->elementTag.'>)/i';

// On save the content of the field on the 505.html file
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
  
    $page = $event->arguments[0];

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);
    $field = $this->fieldName;

    $content = preg_replace($this->regex, '$1'.$page->$field.'$3', $content);

    file_put_contents($file, $content);

});

// On render the edit page, save the content of 505.html file on the field to show it
$this->addHookBefore("ProcessPageEdit::buildFormContent", function(HookEvent $event) {
  
    $page = $event->object->getPage();

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);

    preg_match($this->regex, $content, $matches);

    if($matches) {

        $page->of(false);
        $field = $this->fieldName;
        $page->$field = $matches[0];
        $page->save($this->fieldName);

    }

});

 

The above code assumes that your "505.html" file has a <div> with the id "message" in it, you just have to adapt it to yours.

  • Like 2

Share this post


Link to post
Share on other sites

one thing that is not working for me with the offline files in the template folder:

it seems that if you use delayed output, then there is something in the output buffer already that gets prepended to the html file when rendered;

not sure how to fix this, but it's kind of a problem, can't render a clean 500 error page because of this, due to a bunch of markup being output above the opening <html of the error file...

Share this post


Link to post
Share on other sites
On 3/28/2017 at 2:48 AM, diogo said:

And here goes some code. Place this on site/ready.php (or create a module from it) and edit the first lines to your liking:

 


/*************************/
/******* EDIT HERE *******/
/*************************/

// ID of the page where the custom content is
$this->pageID = 1;

// name of the field where the custom content is
$this->fieldName = 'body';

// name of html tag and id from the parent of the custom content on the 505 file
$this->elementTag = 'div';
$this->elementID = 'message';

/*************************/
/******* END EDIT ********/
/*************************/


// regex to get the contents of parent element
$this->regex = '/(<'.$this->elementTag.'\sid=("|\')?'.$this->elementID.'("|\')?>)([^<]|<.+>.*<\/.+>)+(<\/'.$this->elementTag.'>)/i';

// On save the content of the field on the 505.html file
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
  
    $page = $event->arguments[0];

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);
    $field = $this->fieldName;

    $content = preg_replace($this->regex, '$1'.$page->$field.'$3', $content);

    file_put_contents($file, $content);

});

// On render the edit page, save the content of 505.html file on the field to show it
$this->addHookBefore("ProcessPageEdit::buildFormContent", function(HookEvent $event) {
  
    $page = $event->object->getPage();

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);

    preg_match($this->regex, $content, $matches);

    if($matches) {

        $page->of(false);
        $field = $this->fieldName;
        $page->$field = $matches[0];
        $page->save($this->fieldName);

    }

});

 

The above code assumes that your "505.html" file has a <div> with the id "message" in it, you just have to adapt it to yours.

Thanks @diogo  for this.

___________________________________
Get Assignment help.

Edited by adrian
Removed spammy link
  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By jds43
      Hello,
      Does anyone have experience with migrating content from Django to Processwire? Or are there any suggestions for achieving this?
    • By Brawlz
      Hi,
      I hope this is the correct section for my problem.
      All I need is a connection to an external Database and a query gettings some data. I do this in a processwire Page-Template. I am honestly not sure if it is a problem with processwire or my code:
      $host = ‚XXXXX’; $user = ‚XXXXX‘; $pass = ‚XXXXX‘; $db = ‚XXXXX‘; $port = ‚3306‘; $mydb = new Database($host, $user, $pass, $db , $port);  $result = $mydb->query("SELECT * FROM char“);  while($row = $result->fetch_assoc()) {  print_r($row);  }  
      Produces the following error:
      Error: Exception: DB connect error 2002 - Connection timed out (in /customers/9/4/e/XXXX.de/httpd.www/wire/core/Database.php line 79)
       
      I also tried connecting without the $port variable but got the same error.
    • By Mobiletrooper
      Hey Ryan, hey friends,
      we, Mobile Trooper a digital agency based in Germany, use ProcessWire for an Enterprise-grade Intranet publishing portal which is under heavy development for over 3 years now. Over the years not only the user base grew but also the platform in general. We introduced lots and lots of features thanks to ProcessWire's absurd flexibility. We came along many CMS (or CMFs for that matter) that don't even come close to ProcessWire. Closest we came across was Locomotive (Rails-based) and Pimcore (PHP based).
      So this is not your typical ProcessWire installation in terms of size.
      Currently we count:
      140 Templates (Some have 1 page, some have >6000 pages)
      313 Fields
      ~ 15k Users (For an intranet portal? That's heavy.)
      ~ 195 431 Pages (At least that's the current AUTOINCREMENT)
       
      I think we came to a point where ProcessWire isn't as scalable anymore as it used to be. Our latest research measured over 20 seconds of load time (the time PHP spent scambling the HTML together). That's unacceptable unfortunately. We've implemented common performance strategies like:
      We're running on fat machines (DB server has 32 gigs RAM, Prod Web server has 32gigs as well. Both are running on quadcores (xeons) hosted by Azure.
      We have load balancing in place, but still, a single server needs up to 20 sec to respond to a single request averaging at around about 12 sec.
      In our research we came across pages that sent over 1000 SQL queries with lots of JOINs. This is obviously needed because of PWs architecture (a field a table) but does this slow mySQL down much? For the start page we need to get somewhere around 60-80 pages, each page needs to be queried for ~12 fields to be displayed correctly, is this too much? There are many different fields involved like multiple Page-fields which hold tags, categories etc.
      We installed Profiler Pro but it does not seem to show us the real bottleneck, it just says that everything is kinda slow and sums up to the grand total we mentioned above.
      ProCache does not help us because every user is seeing something different, so we can cache some fragments but they usually measure at around 10ms. We can't spend time optimising if we can't expect an affordable benefit. Therefore we opted against ProCache and used our own module which generates these cache fragments lazily. 
      That speeds up the whole page rendering to ~7 sec, this is acceptable compared to 20sec but still ridiculously long.
      Our page consists of mainly dynamic parts changing every 2-5 minutes. It's different across multiple users based on their location, language and other preferences.
      We also have about 120 people working on the processwire backend the whole day concurrently.
       
      What do you guys think?
      Here are my questions, hopefully we can collect these in a wiki or something because I'm sure more and more people will hit that break sooner than they hoped they would:
       
      - Should we opt for optimising the database? Since >2k per request is a lot even for a mysql server, webserver cpu is basically idling at that time.
      - Do you think at this point it makes sense to use ProcessWire as a simple REST API?
      - In your experience, what fieldtypes are expensive? Page? RepeaterMatrix?
      - Ryan, what do you consider as the primary bottleneck of processwire?
      - Is the amount of fields too much? Would it be better if we would try to reuse fields as much as possible?
      - Is there an option to hook onto ProcessWires SQL builder? So we can write custom SQL for some selectors?
       
      Thanks and lots of wishes,
      Pascal from Mobile Trooper
       
       
    • By Sergio
      All of a sudden, with nothing changed on the database or server, a website was getting error when doing a search:
      Error: Exception: SQLSTATE[HY000]: General error: 23 Out of resources when opening file './your-database-name/pages_parents.MYD' (Errcode: 24 - Too many open files) (in /home/forge/example.com/public/wire/core/PageFinder.php line 413) #0 /home/forge/example.com/public/wire/core/Wire.php(386): ProcessWire\PageFinder->___find(Object(ProcessWire\Selectors), Array) #1 /home/forge/example.com/public/wire/core/WireHooks.php(723): ProcessWire\Wire->_callMethod('___find', Array) #2 /home/forge/example.com/public/wire/core/Wire.php(442): ProcessWire\WireHooks->runHooks(Object(ProcessWire\PageFinder), 'find', Array) #3 /home/forge/example.com/public/wire/core/PagesLoader.php(248): ProcessWire\Wire->__call('find', Array) #4 /home/forge/example.com/public/wire/core/Pages.php(232): ProcessWire\PagesLoader->find('title~=EAP, lim...', Array) #5 /home/forge/example.com/public/wire/core/Wire.php(383): ProcessWire\Pages->___find('title~=EAP, lim...') #6 /home/forge/example.com/public/wire This error message was shown because: you are logged in as a Superuser. Error has been logged.  
      I tried several things, listed in this thread: https://serverfault.com/questions/791729/ubuntu-16-04-server-mysql-open-file-limit-wont-go-higher-than-65536
      But for some reason, MySQL was not getting its limit increased, but in the end, the one that did the trick was this:
      This worked for me on Ubuntu Xenial 16.04:
      Create the dir /etc/systemd/system/mysql.service.d
      Put in /etc/systemd/system/mysql.service.d/override.conf:
      [Service] LimitNOFILE=1024000 Now execute
      systemctl daemon-reload systemctl restart mysql.service Yes indeed, LimitNOFILE=infinity actually seems to set it to 65536.
      You can validate the above after starting MySQL by doing:
      cat /proc/$(pgrep mysql)/limits | grep files
    • By bot19
      I've never encountered this issue before. My local installing is using AMPPS 3.7, setup about 3 months ago.
      Everything was working fine last night, and I think possibly this morning, before it complete stopped with these errors. Please see below.
      I have not changed any config setttings, access settings.
      The only 2 other things I did yesterday was log into phpmyadmin and export the DB, then I think an Xcode update was installed yesterday.
      Can anyone help?
      I know people have run into these issues when they migrate, but I haven't migrated, setup, changed anything.
      Some people have said to just disable to do something like:
      $cfg['Servers'][$i]['AllowNoPassword'] = true; In phpMyAdmin's config.inc.php file. I tried but that didn't work.
      I even tried changing:
      $config->dbHost = 'localhost'; to 127.0.0.1, in site/config.php but no good.


×
×
  • Create New...