CutCodeDown

Squire / Paladin => Squire/Paladin General Discussion => Topic started by: Jason Knight on 9 Nov 2020, 11:05:06 am

Title: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 9 Nov 2020, 11:05:06 am
Squire 3 / Paladin X.3 -- Rebuilding from the ground up.

We're getting a bit off the topic of routing given the number of people who seem interested in my custom "poor man's CMS" and even full blown CMS approach... so I'm going to start a separate thread for discussion of how it works and the reasons I make the decisions that go into it.

For now we have Squire and a poor man's CMS as a working demo here:

https://cutcodedown.com/for_others/squire3/

Squire is my term form various helper functions/classes I use to make a poor man's CMS. Squire consists mostly of:

1) Session Handling

2) The "Request" static object that handles parsing $_SERVER['REQUEST_URI'] providing "one index to rule them all" with user friendly URI's. (The people who call them "search friendly" are talking out their arses BTW!)

3) A "Settings" static object that allows loading from .ini files and/or setting via getters and setters. .INI values are considered "inviolate" and can only be accessed via getters by normal code. If you try to set a value that was pulled from a .ini that set is ignored. Kind of...

4) My general approach to templates, where there's a loadTemplate function to pull the appropriate sub-template files, which are filled with template_name functions like template_header and template_footer  to which data is passed.

Basically Squire is the baseline tools needed to build a "poor mans CMS" (aka just gluing static files together). It is the closest I usually ever come to a "framework". Note that the template style/markup itself and the demo static pages are NOT considered part of "Squire". I simply added enough to show how the parts of squire are used.

Hence concerns about the existing template -- which was a stopgap copy of a WIP from another project -- are mostly irrelevant to the discussion.

Paladin is my term for any fully developed CMS I build based upon Squire. Traditionally these are turnkey to meet the client's specific needs, not a generally organized system.  The next

As a rule of thumb I don't believe in off the shelf answers when it comes to database or "action" parts of building a site. One size fits all usually fits none, and I've always found it easier to do those on a case-by-case basis, rather than having a completed starting like that I have to "run backwards" undoing code to adjust to the client's needs.

With most existing systems that's always what happens; the client wants something it doesn't do out of the box, so you spend far more time undoing the OOB experience and trying to fit client wants to what already is, than you would simply starting over from scratch with the bare necessities, the simple bear necessities, forget about your worries and your strife.

Alright, I'm going to try moving a few of the comments that have nothing to do with "routing" into this thread, and then when I have the time I'll start documenting what "already is" in preparation for the next step.

That next step being that I'll turn it into a database driven blogging system. We'll start with a primitive user and permission system, and work our way out from there.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: xmohamadx on 9 Nov 2020, 01:39:04 pm
... and done.

Live copy here:
https://cutcodedown.com/for_others/squire3/live

full archive here:
https://cutcodedown.com/for_others/squire3/squire3.rar

I'll use what little time I have left before the client meeting to start doing some proper documentation of the how/what/why of it.

Oh, man! such a clean and nice design!
I'm totally disappointed after seeing this demo, while I'm trying hard to design almost a similar website to this demo for more than a month, but you did it in two days I think!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 10 Nov 2020, 03:11:15 am
I'm hijacking this thread for a second, as the mod-rewrite doesn't seem to work on my local install - I was being nosey...

I get the default apache error if I visit: [myURL]/CutDownCode/Squire3/aBunchOFGobbledegook and not the styled  404 error as shown here (https://cutcodedown.com/for_others/squire3/live/aBunchOFGobbledegook).

I guess ModRewrite issue? can the .htaccess file be being ignored?

Sorry for hijacking the thread!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 10 Nov 2020, 08:01:13 am
Which is why I thought it was a mod_rewrite issue - yes it was a manual install of Apache! :)

Thanks! :)
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 10 Nov 2020, 09:07:46 am
I guess ModRewrite issue? can the .htaccess file be being ignored?
The rewrite rule is the core of how "one index" works. Without it, no... none of this will work. You either need it as a .htaccess or placed in your httpd.conf or virtual hosts file.

It's odd for such a central part of Apache would be broken or not installed, even on a local copy. I mean yeah, out of box it's disabled if you manually install it, but it's one of the first things that one usually turns on. Does a "sudo a2enmod rewrite"fix it, or is "AllowOverride All" missing from the vhosts?

This is why for local testing I prefer either running a full VM server install, or an off the shelf all-in-one like XAMPP.
Sorry for hi-jacking the thread!

This code looks as it is something I could tweak to suit my needs - Am I free to do that and use your code?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 11 Nov 2020, 01:25:26 am
@Jason Knight

I managed to TEMPORARILY install the source code and add a couple of amendments.

One addition was to replace the footer with W3.org validation links  for every page.  The infuriating  HTML validation have been removed :)

Application Flow Chart
Another addition was to add an Application Flow Chart image from another PHP Framework. 


https://thisisatesttoseeifitworks.tk/deathshadow/ (https://thisisatesttoseeifitworks.tk/deathshadow/)

Is it possible for anyone to create an Application Flow Chart for this framework?

Observation
I missed having PHP view files and far prefer them because I can change then according to the environment, etc

<?php  // example view file
$tmp = LOCALHOST ? 'small.jpg' : 'large.jpg';
echo '<img src="' .$tmp .'" alt="myImage">';


I am also curious about adding a database and if this would ever be a replacement for the popular PHP Frameworks.

Looking forward to the GitHub version.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 11 Nov 2020, 07:57:27 am
One addition was to replace the footer with W3.org validation links  for every page.  The infuriating  HTML
\validation have been removed :)
Which is a total pointless waste of bandwidth, since normal users don't give a flying ****.

And by fixing the X-UA, you broke the entire reason it's there! The entire reason it is there being to tell IE 10 and 11 to obey IE CC's, since my intent is to tell ALL versions of IE to go suck it in terms of CSS and JavaScript.

You have "broken" it for IE 10 and 11 by "fixing" that ALLEGED "error"... again why I tell HTML 5 validation to f*** off at this point.  JUST as omitting "projection" and "tv" from the media target breaks it for specific UA's like many kiosks and settops.

"fixing" said claims by the W3C of things that are NONE of the HTML specifications flipping business breaks things. Hence why "valid HTML" with this living document BULL is as much of a pipe dream as CSS validation was a decade ago.

NOT saying don't check it, but know which errors are total nonsensical mentally enfeebled "eye cans haz teh intarwebs" BULL!

Seriously, open your version of the page in IE11... now open my copy in same.

IE11, X-UA-Compatible IE=9, conditional comments strip off all broken CSS and Scripting:
(https://cutcodedown.com/for_others/squire3/screenshots/x-ua-IE9.png)

IE11, X-UA-Compatible IE=edge, conditional comments are ignored and the page is a broken mess of broken non-working components.
(https://cutcodedown.com/for_others/squire3/screenshots/x-ua-edge.png)

And that is why I lack the words to use in polite company when it comes to the ****wit halfwit dumbass pedantic nonsensical BS changes they've made to HTML 5 over the past year or three. More so when there's ZERO blasted version tracking in document so yesterday's HTML 5 is invalid today, and today's HTML 5 has the potential to be invalid tomorrow.

It's the straw that broke the camel's back in my love-hate relationship with the W3C. They've gone from a well intentioned group of wishful thinkers pretending to be a standards body, to an abusive, manipulative, and duplicitous abusive spouse we're not "Allowed" to divorce.

Another addition was to add an Application Flow Chart image from another PHP Framework.
Ah, a flow chart... how quaint... in a "horse and buggy" career educator rel;ic of the early '80's (at best).

"Hello computer... a keyboard? How quaint!" -- Scotty

Is it possible for anyone to create an Application Flow Chart for this framework?
Always possible, though the architecture logic isn't orthagonal; which is oft where flowcharts go bits -up. Much like the CISC vs. RISC debate, where one has the opcodes created as efficient as possible for performance and the support hardware (RAM, disk, BUS), whilst the other shoe-horns them into an organized grid where it's very efficient on the CPU die, but painfully inefficient for everything connected to it. Which is why ARM is cheap, very power efficient, and will NEVER match x86 on performance per clock or memory efficiency.

Orthagonal coding -- which is what a lot of those pesky "programming paradigms" try to be -- amounts to creating inflexible systems. They have a single over-reaching plan that often doesn't fit or allow for things to go outside their lines. MVC is an example of this where whilst it might make sense in certain very small corner cases -- event driven programming where it's single view-stack -- it's often a bloated pointless wreck when shoe-horned into request driven programming. (which PHP used for websites is most definitely request driven, not view driven).

This "square" layout that fits into nice pretty flowcharts is the proverbial round peg square hold problem. You pound hard enough it fits, doesn't make it right.

Also for the love of whatever flavor fairy tale genocidal maniac in the sky you happen to subscribe to, don't call this a framework. At best it's a "poor man's CMS" and that will change when I have the time to add database and user handling... which is around 70% complete with me plucking away it in my spare time between actual client proposals and some paying side-work doing builds and repair. Got a socket 1366 Xeon workstation on the bench right now that won't stay powered on and/or randomly loses video. Trying to convince the owner it's far past time to upgrade, and to buy a win10 license since they're on a bootleg of 8.1

I missed having PHP view files and far prefer them because I can change then according to the environment, etc

<?php  // example view file
$tmp = LOCALHOST ? 'small.jpg' : 'large.jpg';
echo '<img src="' .$tmp .'" alt="myImage">';

The what now? I know what "views" are in JavaScript and the concept doesn't make a lick of sense for PHP, and if we were to talk views, that's not it.

It's also policy in how I write this that in normal echo commas are favored over string addition. Uses less memory and executes faster.

That's also a "variable for nothing" ... and you can go ahead and do that in the template or the content generation so I'm not quite sure what you're "missing".

Code: [Select]
echo '
  <img src="', LOCALHOST ? 'small.jpg' : 'large.jpg' , '" alt="describe this properly!">';
Though when choosing a large or small image, that's typically the <picture> tag's job... well, at least it is if you tell IE to sod off.

I am also curious about adding a database and if this would ever be a replacement for the popular PHP Frameworks.
That is the next step to half-answer @benenaman's request, though overall what he's talking about and what I do and/or would do and/or would let clients do isn't even in the same galaxy, much less ballpark.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 11 Nov 2020, 10:35:22 am
Just a quick note because it is quite late here.

The page displays fine on the three systems I tried which were Linux desktop, Apple iPad Mini and an Android Motorola mobile. Tomorrow  I will try and find an emulator to replicate the broken display.

I also noticed the page is stuck on portrait mode and does not flip into landscape?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 11 Nov 2020, 11:04:22 am
The page displays fine on the three systems I tried which were Linux desktop, Apple iPad Mini and an Android Motorola mobile.
NONE of which pay any attention to the X-UA-Compatible META. It is 100% browser specific to IE, which is why the HTML 5 specification should have ZERO BLASTED BUSINESS caring what it's for or what its values are.

In fact, this sets a dangerous precedent. META tag are supposed to be for UA or developers to use to create whatever values they want. Like the keywords and description META were NOT created by the W3C, they were made by search engines under the rules for META.

META literally exists for the purpose of letting us declare name/content pairs however we like. That's what it's for. For them to say that a specific value is or isn't valid in HTML 5 defeats the entire blasted reason the tag even EXISTS!

This goes above and beyond when it comes to the level of ***ing STUPID the HTML 5 specification continues to morph into. It had a weak start to begin with undoing most of the reasoning behind HTML 4 Strict, but lands sake this is ridiculous.

Every blasted month for ten years, there's just been one more reason to tell the W3C to go **** themselves. The stupid at this point hurts and is starting to go above my pay grade.

I also noticed the page is stuck on portrait mode and does not flip into landscape?

What does portrait/landscape  have to do with layout? If there's enough EM width in either to show the layout as is, the layout is shown as is. The media queries are NOT based nor should they be based on specific sizes or aspect ratios, but on the needs of the content.

And portrait/landscape on WHAT exactly? Your tablet? My tablet? Your phone? My phone? With them all having different resolutions and aspect ratios, you can't just say "portrait" or "landscape" as what's good for one will be illogical junk for another.

That's why designs pre-planned for aspect ratio or specific px widths are almost always broken junk for someone somewhere at some time. See Bootcrap's dumbass "grid" and media query idiocy.

Where if you don't know what's wrong with their s, m, l, xl, xxl rubbish and how it's implemented, you probably shouldn't be creating frontends.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 11 Nov 2020, 01:21:45 pm
Oh, one more thing about:
The infuriating  HTML validation have been removed :)
The removal of aria-hidden="true" results in those elements showing up in some screen-readers like Jaws 2018/earlier. Because the blind are often stuck using decade out of date versions (since they're disabled and the software costs thousands) legacy support on things like "hidden" is important.

... and the "hidden" attribute? It's too new. Aria-hidden="true" predates it by about five years, so UA support is more likely to have the aria version than the HTML 5 one. Worse, desktop UA's (browsers) tend to ignore aria roles outright!

As such we NEED both; to blazes with the W3C's opinion on that. Pedantic bullshit like that is out of touch with real world deployment. Almost as if the 500 pound gorilla's over there are the browser makers, and so far as they're concerned people who actually build websites can sod off.

As evidenced by the language used in their ALLEGED "specification"! And it takes giant brass donkey balls to call HTML 5 a "specification" with a straight face if you know the first blasted thing about engineering!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 12 Nov 2020, 01:11:38 am
@Jason Knight,
Quote
Which is a total pointless waste of bandwidth, since normal users don't give a flying ****.
I find it ideal for validating HTML errors, one click reveals all anomolies.


Quote
And by fixing the X-UA, you broke the entire reason it's there! The entire reason it is there being to tell IE 10 and 11 to obey IE CC's, since my intent is to tell ALL versions of IE to go suck it in terms of CSS and JavaScript.
The screendump was not the web page on my site because the link names are different and there are no avatar images?

Quote
Seriously, open your version of the page in IE11... now open my copy in same.
I do not have Windows and therefore cannot test. I tried a couple of emulators and the web page displays without any distortion? Can someone else try the actual page and provide a screendump.

Quote
Ah, a flow chart... how quaint... in a "horse and buggy" career educator rel;ic of the early '80's (at best).

"Hello computer... a keyboard? How quaint!" -- Scotty
I have always found charts useful especially when trying to comprehend a wall of text.

Quote
The what now? I know what "views" are in JavaScript and the concept doesn't make a lick of sense for PHP, and if we were to talk views, that's not it.
I think PHP Frameworks and CMSs all have views because they try to separate functionality similar to MVC structures. I thought my example was easily comprehended at glance and can always be optimised. I also thought the demo and source code was a replacement for PHP Router Frameworks. Can the source code not be adapted for other sites?

Quote
What does portrait/landscape  have to do with layout? If there's enough EM width in either to show the layout as is, the layout is shown as is. The media queries are NOT based nor should they be based on specific sizes or aspect ratios, but on the needs of the content.
I expected that the web page would flip when the mobile was rotated?

Looking forward to updates rather than rants when others anomolies.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 12 Nov 2020, 09:31:54 am
I find it ideal for validating HTML errors, one click reveals all anomolies.
I use the web developer toolbar for that.
https://chrispederick.com/work/web-developer/

It can reveal all sorts of other data that's useful, like a document outline to tell you if your heading orders are shite or not, or turning on/off CSS to test accessibility.

It's just not something that belongs on a live page, this isn't 1998 and the age of "best viewed in Netscape" banners.

The screendump was not the web page on my site because the link names are different and there are no avatar images?
That's because I used my local copy to swap the two values.

I do not have Windows and therefore cannot test.
Which means you've utterly hobbled yourself at web development, and or should have Windows available in a VM.

I tried a couple of emulators and the web page displays without any distortion?
Define "emulators"... do you mean a VM, or do you mean relics of a bygone age that don't accurately represent what IE really does? There's a lot of bullshit IE "testers" out there that just don't work, particularly for details like this.

Kind of like how Chrome and FF's mobile emulation is mostly bullshit.

I have always found charts useful especially when trying to comprehend a wall of text.
I've always found them useless outside academic settings.

I think PHP Frameworks and CMSs all have views because they try to separate functionality similar to MVC structures.
Which as you've probably heard me say dozens of times, shoe-horning MVC into PHP is a complete complexity mismatch. PHP is request driven linear execution, MVC is ideal for event driven... which is why 99%+ of everything I've ever seen done with MVC is bloated convoluted hard to maintain crap.

I thought my example was easily comprehended at glance and can always be optimised.
WHAT it does is easy to comprehend, what it has to do with "views" is utterly beyond me. It's a minor snippet of ternary output that has absolutely nothing to do with the topic being discussed.

I expected that the web page would flip when the mobile was rotated?
Flip? Do you mean rotate? Are you saying when you rotate the display it's not rotating to match? There's nothing present that would/should cause that. Lemme guess, crApple Safari, right? Broken from day one and aging like milk

Looking forward to updates
Might be a bit, paying work comes first.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 12 Nov 2020, 09:51:56 am
Oh, and here's a screenshot of your version broken in IE11.

(https://cutcodedown.com/for_others/squire3/screenshots/x-ua-edge-jb.png)

IE can't handle CSS variables, so the colours are missing, padding is wrong, flex is broken/incorrect, which is why I set IE=9 enabling IE CC's so IE doesn't get the CSS or JS.

... and why I've got exactly two words for the W3C on their "recent" changes to HTML 5.

(https://cutcodedown.com/images/suckIt.webp)
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 13 Nov 2020, 02:49:56 am
@Jason Knight
Quote
I use the web developer toolbar for that.
https://chrispederick.com/work/web-developer/ (https://chrispederick.com/work/web-developer/)
Far too much info and I will strick to my method because I find it quicker.


Quote
Quote from: John_Betong on 2020-11-12, 12:11:38
I do not have Windows and therefore cannot test.
Which means you've utterly hobbled yourself at web development, and or should have Windows available in a VM.
Fortunately web developement is strictly for my personal benefit and does not require Windows :)

I managed to add another web page:

https://thisisatesttoseeifitworks.tk/deathshadow/static/info (https://thisisatesttoseeifitworks.tk/deathshadow/static/info)
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: fgm on 13 Nov 2020, 01:07:48 pm
Thank you for Squire 3 code!
Code: [Select]
class="cards vanilla"
class="cards vanilla framed"
class="cards icons landscape discs"

Aren't vanilla, framed, landscape and discs classes presentational concepts that have no place into HTML? since HTML describes what things are and not how they look.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 13 Nov 2020, 08:21:50 pm
I was going to suggest exactly this. There are a few things in the implementation I wanted to discuss.

In several Php files you have

Code: [Select]
; <?php die(); // prevent direct calls just in case
This doesn't block direct calls. If you could directly access the file you would just get an error. The die never executes. In fact, you don't even get past the starting semi-colon.

Your comments...
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 13 Nov 2020, 08:29:57 pm
In several Php files you have

Code: [Select]
; <?php die(); // prevent direct calls just in case

If a direct call does occur it does die. Why? Because the file is labelled .php and it immediately <?php die()'s. The only thing output if it is called directly is a semi-colon and a space, preventing the comments of the .ini from being output by a http request!

The semi-colon is only a comment in .ini files, so that line with the die is ignored during parse_ini_file, NOT when you call it directly.

Think about it. When called as .php via a direct http call it dies. When called via parse_ini_file the php is ignored because it's inside a ini file comment.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 13 Nov 2020, 08:37:15 pm
Ok, I inadvertently left an opening <?php that my editor writes by default and pasted your code after it. Derp!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 13 Nov 2020, 08:51:22 pm
Aren't vanilla, framed, landscape and discs classes presentational concepts that have no place into HTML? since HTML describes what things are and not how they look.
*DING*DING*DING*DING*DING* we have a winner.

That template is actually an experiment and part of another project. Squire itself has little to do with the markup or CSS being output here. I thought I made that clear enough; guess not.

The experiment in question is to see if I can make a HTML/CSS framework that minimizes the damage done by the concept. These frameworks INHERENTLY use presentational classes, but if the other problem; endless pointless classes for nothing in the markup, non-semantic markup, gibberish markup by people unqualified to write a single blasted line of HTML (see bootstrap), and so forth could be reigned in, how bad would the result be?

I think I'm ok with a few semi-presentational classes that describe the overall concept of the layout, without coming right out and saying "box-shadow text-center" and so forth. It's not saying what "frame" is... is it a border? Is it a box-shadow? Is it a different coloured background? It's just saying that it MIGHT receive "a" style, not what that style "is".

Though "disc" and "porthole" obviously go above and beyond that.

One of the reasons I'm so oft able to stick the knife in and twist where it hurts the most, is I often che-checkity check myself by actually trying the methodologies, or attempting to find compromises and middle grounds, if for no other reason than to make sure I'm not full of shit and my conclusions are sound.

It always feels like there SHOULD be a middle ground, a compromise. I'm still testing and playing so I'm not sure this is viable, but I will say that having all those different layouts based on this single unified markup:

Code: [Select]
<section class="cards">
<h2>Default Cards</h2>
<p>
<code>class="cards"</code>
</p><p>
The default behavior for cards is pretty simple.
</p>
<div class="inner">
<section>
<h3>Heading</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed purus mauris, porttitor eu diam euismod, vestibulum condimentum velit. Fusce pellentesque purus et vestibulum ultricies. Donec sollicitudin consectetur finibus. Quisque malesuada fringilla eros eget maximus. Nunc ornare a mauris sit amet tristique. Integer varius sed lectus quis suscipit. Phasellus sed molestie eros. Vestibulum ut neque vel metus rutrum ultricies.
</p>
<ul class="controls">
<li>
<a href="#">
View Details
<i class="fas fa-angle-double-right"></i>
</a>
</li>
</ul>
</section><section>
<h3>Heading</h3>
<p>
Sed egestas metus in auctor bibendum. Ut gravida ligula a diam gravida, non convallis nisl lacinia. Sed at lorem ex. Quisque maximus ex vel odio malesuada, ut venenatis massa posuere. Nulla eu turpis blandit, varius ligula eu, elementum nisi. Vestibulum nec posuere purus, ut condimentum nulla. Pellentesque lorem ipsum, eleifend vitae vulputate eu, scelerisque sed elit. Pellentesque at malesuada nulla, quis fermentum magna.
</p>
<ul class="controls">
<li>
<a href="#">
View Details
<i class="fas fa-angle-double-right"></i>
</a>
</li>
</ul>
</section><section>
<h3>Heading</h3>
<p>
Morbi lobortis, lacus a dignissim iaculis, dolor massa ultrices augue, id maximus nunc quam pulvinar nulla. Suspendisse arcu augue, aliquam vitae ultrices ac, venenatis a mi. Ut erat ex, tincidunt et sagittis nec, pharetra eget odio. Nunc porta risus augue, nec consectetur nisi rhoncus sed. Donec vel sapien eu lacus volutpat blandit. Nam porta elementum ante nec efficitur. Maecenas ultrices sed mi ac tincidunt.
</p>
<ul class="controls">
<li>
<a href="#">
View Details
<i class="fas fa-angle-double-right"></i>
</a>
</li>
</ul>
</section>
<!-- .inner --></div>
<!-- .cards --></section>

Where all I have to do is change the outermost element's classes has a lot of appeal.

That's the compromise I'm trying to find to try and make a framework that doesn't COMPLETELY suck. It's going to suck in a specific way, but if I can isolate that suckage to a single container for each section, perhaps I won't have to tell the whole concept to suck it.

I'm TRYING to be open to the concept. Even if I've railed against it for a decade and a half. I do this every five or six years since big ****s in your *** are bad for your health.

And there is appeal, I mean look at the difference between the above subsections, and an image one:

Code: [Select]
<section>
<picture>
<source srcset="/paladin3/images/avatars/curly.webp" type="image/webp">
<img
src="/paladin3/images/avatars/curly.jpg"
alt="Curly Howard"
loading="lazy"
>
</picture>
<div>
<h3>Curly Howard</h3>
<p>
The funniest of them all
</p>
</div>
</section>

All that gets added is the picture/img and a DIV, the wrapping parent section getting a different class, and done. The semantics does the heavy lifting without the flaw of throwing endless mindless stupid dumbass presentational classes at everything.

TRYING to find that safe middle ground between the ideal and what/how "normies" want it to work.

That make any sense, or am I wasting my time trying to be a bit less radical about it?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 13 Nov 2020, 08:52:05 pm
Ok, I inadvertently left an opening <?php that my editor writes by default and pasted your code after it. Derp!

Happens to the best of us... frequently.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 14 Nov 2020, 12:42:19 am
In several Php files you have

Code: [Select]
; <?php die(); // prevent direct calls just in case

If a direct call does occur it does die. Why? Because the file is labelled .php and it immediately <?php die()'s. The only thing output if it is called directly is a semi-colon and a space, preventing the comments of the .ini from being output by a http request!

The semi-colon is only a comment in .ini files, so that line with the die is ignored during parse_ini_file, NOT when you call it directly.

Think about it. When called as .php via a direct http call it dies. When called via parse_ini_file the php is ignored because it's inside a ini file comment.

Is there any reason that the "system files " are not installed above the root similar to the majority of modern PHP Frameworks and CMSs?

I find that using a PHP extension as a INI file is tremendously confusing.

Does this apply to all PHP named files with a leading ;
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 14 Nov 2020, 08:19:03 am
Is there any reason that the "system files " are not installed above the root similar to the majority of modern PHP Frameworks and CMSs?
Excellent question... and in general the answer is that said practice is mostly placebo nonsense.

1. The rewriterule prevents direct access to files not on its whitelist. ANYTHING not on the approved list of directorys or extensions is rerouted to index.php

https://cutcodedown.com/for_others/squire3/live/template/default/common.template.php

The file is there, but it 404's because that's not a valid "Request".

Code: [Select]
RewriteEngine On
RewriteRule !(^(images|downloads))|(\.(gif|jpg|png|css|js|html|txt|ico|zip|rar|pdf|xml|mp3|mp4|mpg|flv|swf|mkv|ogg|avi|woff|woff2|svg|eot|ttf|json|webmanifest)$) index.php

If it's not on that list, and it's not a valid "Request", it will 404.

2. Most of the files output nothing if called directly, and the few that do contain no security or safety related actions. This "second ring" of protection is just good practice, and it's why the .ini file "die" is helpful as is that good practice of the majority of include() only containing functions and classes.

3) Anything that can access the files via non http methods can usually access it regardless of where you put it.

4) Many FTP logins do NOT give you access to directories above the HTTP root. It's increasingly less common, but by not trying to play that silly game it increases the audience and the hosting choices.

I find that using a PHP extension as a INI file is tremendously confusing.
It's a bit like banging your head into the wall. You get used to it. :P

More important though is to stop thinking about file extensions as just the LAST period onward. Indeed the proper behavior is supposed to be everything from the first period onward which is how a great many systems handle that. It's not a ".php" file, it's a ".ini.php" file.

Does this apply to all PHP named files with a leading ;
No, because you don't "parse_ini_file" other PHP files.

look in "/libs/common.lib.php" at the Settings.lib.php, these .ini.php are loaded via parse_ini_file, not readfile, include, or require.

It's a fun way to store data that http direct calls will bomb on... and with two rings of security there's no reason to crush portability by using that third silly method. Especially given the number of hosts where you might not even have access to create files above the http root.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: fgm on 14 Nov 2020, 08:32:08 am
That template is actually an experiment and part of another project. Squire itself has little to do with the markup or CSS being output here. I thought I made that clear enough; guess not.
Oh, I came from To Route Or Not To Route - The Definitive Guide??? (https://forums.cutcodedown.com/index.php?topic=362.0) thread so I didn't read the first post. It's crystal clear now.

I really like a basecode to organize a website from scratch independently from the template used, and also the idea to offer an almost sane bootcrap alternative -- with or without Squire. Good job!
That make any sense, or am I wasting my time trying to be a bit less radical about it?
In my humble opinion, the use of section and nav bloat plus presentational classes like landscape somewhat defeat the pureness of HTML, but I suppose it's reasonable to achieve that middle ground as an starting point for developers accustomed to the typical frameworks.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 14 Nov 2020, 09:52:09 am
In my humble opinion, the use of section and nav bloat plus presentational classes like landscape somewhat defeat the pureness of HTML, but I suppose it's reasonable to achieve that middle ground as an starting point for developers accustomed to the typical frameworks.
Thing is where they are in the code are places that if I lacked them, I'd end up having to put DIV with classes from a layout perspective. As such they actually save me some code.

Though the "pureness" thing is why I dislike it... but something I'm always trying to remind myself -- and others -- of is it's not about ME. It's not about YOU. It's about trying to reach everyone.

And sometimes that means throwing even the best intentioned of rules in the trash. Even mine.

I honestly think that if I can meet the framework fanboys halfway, placing the emphasis on semantics and pre-constructed and uniform HTML structures, I might be able to drag them away from throwing classes at everything and using purely presentational classes like text-red or box-shadow.

Especially if I can show how much simpler the basic markup is.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 14 Nov 2020, 12:23:54 pm
On the technical side... index.php line 76 you call

Code: [Select]
action_content($data);
and pass one parameter, $data. The actual function in test.content does not accept any parameters. Oversight?

While we are in test.content.php, why put what is nearly 100% html in a function and echo it out?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 14 Nov 2020, 03:03:44 pm
and pass one parameter, $data. The actual function in test.content does not accept any parameters. Oversight?
Foresight.

When databases or dynamic sites are involved the various $startup will plug data into them to be shown. It's part of the separation of concerns.

Not all pages will use them, but the mechanism is provided irregardless.

For example, if we had BLOGS a single blog entry would be:

Code: [Select]
$data['action_blog_entry'] => [
  'title' => "Blog Titlte",
  'content' => "Your paragraphs of content and so forth"
];

Whereas

Code: [Select]
$data['action_blog_listing'] => [
  'title' => 'Directory Title',
  'stmt' => $stmt // the PDO statement linking to each of the blog entries
];

Note, I'll be extending PDO to allow for statements to be "locked", preventing their re-use if desired. part of preventing exposure of the interface to PHP execution in places it has no business like the template.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 14 Nov 2020, 11:44:03 pm
@Jason Knight,
I have uploaded Squire 3/ Paladin X.3 and also added another web-page and now concerned with future PDO changes...

When the PDO changes arrive will I have to install the complete project again and add my web-pages or will I be able to only add the "system files"?

I like the way the Github CodeIgniter Framework separates the System and Application files into two separate directories which simplifies essential security upgrades and improvements.

Are you considering a Github Squire 3/ Paladin X.3 repository?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 15 Nov 2020, 09:46:54 am
When the PDO changes arrive will I have to install the complete project again and add my web-pages or will I be able to only add the "system files"?
The changes should be able to co-exist. There is one major change but so long as you've not messed with the index.php (which users of the system should treat as inviolate) it should be fine.

Right now what's there isn't true "Paladin", more a placeholder to show off the components of Squire. When it becomes Paladin -- since even most of the index.php gets moved into a main.lib.php and a main() instead of IIFE -- the existing functionality of /actions/ remains largely unchanged. Statics are statics, though one could move them out of being static files and into the DB.

I like the way the Github CodeIgniter Framework separates the System and Application files into two separate directories which simplifies essential security upgrades and improvements.
That involves having a separation of "system" and "application" which to me isn't where the line should be drawn or even a "thing" that should be. The two words mean the same thing to my mind so that separation just makes things HARDER, particularly upgrades and improvements.

The closest I get to that is the difference between library (system), actions (application?) and output.

Are you considering a Github Squire 3/ Paladin X.3 repository?
I don't GIT. I've watched it **** too many projects, let too many "project managers" sleaze by on not doing their damned jobs, and in general for anything simpler than an OS kernel it's a total and complete complexity mismatch. When a project has multiple workers is it so blasted hard to submit proposed changes to an actual flipping person who rides herd with accept/reject, and to set master code milestones via a lousy shell file or even just ^C^V?

I find GIT to be painful to use, painful to work with, and like a great many allegedly "useful" tools it just gets in my damned way! Hence why most people who use GIT seem to be a bit like eMacs wankers; they swaste ridiculous amounts of time dicking with the system that could have been better spent writing code! Like how people who program in eMacs spend more time dicking with macro's than doing anything useful.... and remember, I'm an assembler programmer, I know all about when and where macro's are useful.

Simply put, it doesn't fit my workflow, mindset, or methodologies. I can't work with it without the overwhelming urge to put my fist through the display.

But to be fair, there's a LOT of stuff in this industry people talk about being "easy", "simple", or "better" when it comes to tools or methodologies, where I honestly have ZERO huffing clue what the **** people are talking about. From convoluted train wreck messes like version control and "programming models", all the way down to simple stuff like colour syntax highlighting, code completion, and tabbed editors. For me many of these things take the simplest of tasks and make them as painful and difficult to do as possible. Typically because the people who CREATED this stuff weren't qualified to write software in the first place.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 15 Nov 2020, 09:53:36 am
Oh, and for the curious, the new index.php when it becomes paladinX

Code: [Select]
<?php

/*
index.php
Paladin X.3 (Squire 3.0) "one index to rule them all"
Jason M. Knight, November 2020
*/

include('libs/main.lib.php');

main(
'mysql:dbname=paladinx.3;host=localhost'// dsn
'paladinTesting'// username
''// password
[
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);

The index itself becomes a config file for the DB.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 15 Nov 2020, 10:48:26 am
Alright, before I start showing the database stuff, I really want to talk about the architecture of this system. Sadly I've not been able to devote a lot of time into this the past week because, well... this is basically the equivalent of a normal client project, just without the paying clients. Guess who takes precedence.

Being Sunday and waiting for a client to get back to me which won't happen 'til tomorrow, I've got all day for this. Maybe I should mark Sunday as my day to work on this full time? A number of you seem enthused and interested, and it seems as good a hobby project as any to turn into a full blown CMS for the "normies".

Now, I do these types of file by file function by function breakdowns EVERY time I write a system like this, as not just a reference for myself and others, but as part of my debugging and refactoring process. It's amazing how often I'll find mistakes just by doing this.

The general architecture for this closely matches how PHP and HTTP requests work. HTTP is request driven, the request is our event. The HTML once CLIENT SIDE is what some programming models would consider the "view", where server side it's just "output". This is where IMHO MVC is a complexity mismatch as it tries to shoe-horn server side only many concerns that have no business on the server.

Hence if one were to make a cutesy acronym that sums up this programming model, it would be IPO.

Input > process > output

"Input" we figure out what the user wants or is trying to do, "process" we perform those actions and gather up any resultant data, then on "output" we glue those results to markup. Some "output" control -- session creation, gzip handling, and so forth -- ends up before input processing just as a safety precaution and so if we need to set things like headers or cookies during "input" or "process" we can.

When it comes to process, the overall concept is that we use the directory system to map user request handlers. Because the "one index to rule them all" is powered by this rewriteRule: (which could be considered part of "input")

Code: [Select]
RewriteRule !(^(images|downloads))|(\.(gif|jpg|png|css|js|html|txt|ico|zip|rar|pdf|xml|mp3|mp4|mpg|flv|swf|mkv|ogg|avi|woff|woff2|svg|eot|ttf|json|webmanifest)$) index.php
Only files in the two directories (images | downloads) and files with the above extensions are allowed to be served normally. ANY request that doesn't match either of those patterns is routed to our index.php where the requested path is parsed out of $_SERVER['REQUEST_URI']

With that in mind, let's just summarize files and each of their subsections.

/index.php -- the main user call.


Note that what much of this file does is part of Squire, the file itself is not. It's just stuff I copy/paste in to wherever is appropriate for the turnkey solution.

Code: [Select]
// before we do ANYTHING else, let's set up gzip compression
foreach (['gzip', 'x-gzip', 'x-compress'] as $type) {
if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], $type) !== false) {
ob_start('ob_gzhandler');
ob_implicit_flush(0);
header('Content-Encoding: ' . $type);
register_shutdown_function(function() {
ob_end_flush();
});
break;
}
}
Blindly starting the gzip compression without manually setting the content-encoding can cause pages to load broken, same for trying to set this from php.ini or httpd.conf. By checking for all three possible compression types we actually can deliver gzipped to more UA's (IE, Konqueror, Blazer) than simply starting ob_gzhandler can handle, and it dodges the issue where Yandex will occasionally not index PHP pages that don't support x-compress as a parameter.

It's just better to manually start it and explicitly ob_end_flush with a shutdown handler.

Have you ever noticed that if you ob_start the zip handler, then try to DIE or PHP outputs an error, the gzip compression ends up mangled and you get a gibberish page? That's what registering a shutdown function to end the buffer accomplishes.

... and by starting output buffering as our first thing, we can header() or set cookies until blue in the face regardless of when/where in the code; even after we have output!

Code: [Select]
session_start();
/*
regenerating the ID on every pageload reduces the time window
in which a session key can be exploited for MITM attacks.
*/
session_regenerate_id();

I'd hope you folks would know what that does by now. I imagine the comment helps. :D

Code: [Select]
/*
prevent displaying site in frame. Some people will say do this
in the httpd.conf or other server config, it takes NO processing
difference here, it's easier to say do it only for our single
entry-way from here, I prefer not to put something this important
outside our portable code, and it's better not to make assumptions
about what server software is in use. Not everyone uses Apache.
*/
header('X-Frame-Options: DENY');

I know a LOT of dev's will say "don't do that from the php" -- why? PHP is going to run anyways, it can set headers, it takes no more processing time -- in fact it can take LESS because we don't need a regex to not blanket apply it from the config files -- and putting it in our single entry point is just simplest.

I see a lot of people get their panties in a knot over using header() for anything but redirects which is funny, I'm the exact opposite. I hate redirects and avoid them whenever possible.

Code: [Select]
/*
Load functions and methods common to all pages
*/
include('libs/common.lib.php');
Speaking of bad commenting practices, did I REALLY have to explain that?

Code: [Select]
/*
Many settings are loaded from ini as the setter and are
only retrievable with a getter.
*/
Settings::loadFromIni(
'default.ini.php',
'user.ini.php'
);
The Settings static object comes from common.lib.php. It can load settings from ini files or directly set them. Values from ini files cannot be directly overwritten, though when it becomes Paladin that will change... slightly. Paladin uses a more complex flavor of this same routine. For now just know that these ini files values are being loaded.

Code: [Select]
define(
'TEMPLATE_PATH',
'templates/' . (Settings::get('template') ?: 'default') . '/'
);

There's an old saying, use define... a lot. No, A LOT!

The template path is a perfect candidate for this. We will need it all over the codebase, it can be handy inside the template itself since our URI's could be almost anything, so let's set it. Once we get to Paladin this value will likely be changed to TEMPLATE_DEFAULT_PATH since the user may have their own value. Multi-skinning -- like most forums offer -- being an essential part of our structure.

Code: [Select]
templateLoad('common');
Loads TEMPLATE_PATH . 'common.lib.pgp' using require_once. See common.lib.php for more. It's just easier to have a function for a method that we call not just here, but inside actions as well. Some actions might need the forms.template.php, others might have their own.template.php.

Note that template_load actually checks for if the file exists in TEMPLATE_PATH, but then also an optional
$action_path parameter. This allows actions to contain their own default template separate from the system one, letting actions be modular. When making separate templates everything falls back on the default or the action. We'll talk about that more in the common.lib.php discussion.

Code: [Select]
/*
IIFE to isolate scope, so a code appendage can't see anything
we want to keep local here just in case. Thankfully PHP now has
proper IIFE
*/
(function() {
Comment says it all. This will become main() in the proper "paladin" system.

Code: [Select]
$action = Request::value();
if (!$action) $action = 'static';
if (!is_dir('actions/' . $action)) httpError(404);
$actionPath = 'actions/' . $action . '/' . $action . '.';
safeInclude($actionPath . 'startup.php');
$data = action_startup();
template_header($data);
if (file_exists($fn = $data['contentFilePath'] . '.content.php')) {
safeInclude($fn);
action_content($data);
}
if (file_exists($fn = $data['contentFilePath'] . '.static')) readfile($fn);
template_footer($data);

We set our $action to be included, reverting to "static" as the default if none is found. We 404 if there's no corresponding action (see httpError in common.lib.php), otherwise we include the startup file.

Startup files are our "process". A normal process handler will return $data to be output (if any) including the "contentFilePath", which can be a PHP file that performs output logic, or a static file, OR BOTH! Note that statics are always loaded after PHP driven content.

The template is auto-added as appropriate. Note that some PROCESS may call the template themselves and then die() for the handling of special cases such as errors.

In a full Paladin system I often condense down httpError  and so forth to methods on a "Bomb" static that also calls error_log.

Alright, gimme a few and I'll do the same for common.lib.php
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 15 Nov 2020, 11:06:57 am
/libs/common.lib.php -- common library functions and methods

Code: [Select]
function cleanString($string) {
return htmlspecialchars(strip_tags($string));
}

function cleanPath($path) {
return trim(str_replace(['\\', '%5C'], '/', $path), '/');
}

Just some common oft used string cleaners.

Code: [Select]
/*
A more robust version of hashCreate should allow for multiple hashes
to be stored of the same name, with an expiration time on it.
*/

function hashCreate($name) {
return $_SESSION[$name] = bin2hex(random_bytes(24));
}

function hashExists($name, $hash) {
return isset($_SESSION[$name]) && ($_SESSION[$name] == $hash);
}

Generates a random hash, or checks for the existence of one. I may make this a more robust Object in Paladin to show what I'm talking about with the comment.

Code: [Select]
function httpError($code) {
include('fragments/httpError.php');
}

function paladinError($title, $desc) {
include('fragments/paladinError.php');
}

One of the few cases where a direct call is allowed to output, though in most cases it would throw an error since the template wouldn't be loaded.

These are dynamically loaded AS NEEDED so that we're not wasting time loading their entire code even when unused. That's a mistake I see in a lot of off the shelf CMS and frameworks is that they'll load full on handlers with their output, even when they're not called.

Code: [Select]
function uriLocalize($uri) {
if (
substr($uri, 0, 4) == 'http' ||
substr($uri, 0, 1) == '#'
) return $uri;
return ROOT_HTTP . $uri;
} // uriLocalize

Handy when working with URI's that you don't know how/where they're rooted, to either plugin or not plugin the full local file path. Used extensively in the template, it can also be useful for in-content links, particularly if trying to avoid full-blown bloated absolute URI's.

Code: [Select]
function templateLoad($name, $actionPath = 'template/default') {
if (
file_exists($fn = TEMPLATE_PATH . $name . '.template.php') ||
file_exists($fn = $actionPath . $name . '.template.php')
) include_once($fn);
else {
error_log(
'unable to find template file for "' . $name . '"'
);
die('template error');
}
} // templateLoad

As you can see this cascades through TEMPLATE_PATH and the optional $actionPath to try and find the corresponding file.

AND YES those are single = as we're testing on assignment! Seriously folks, =, ==, and === are three separate things for a reason, HOW DARE we actually use them for those reasons because a handful of nose-breathers are too stupid to understand them!

The error handling would/should be more robust akin to httpError once we get to "paladin".

Code: [Select]
/*
safeInclude is utterly dumbass, but since PHP just LOVES to
bleed scope all over the place with 1970's style "includes"
we have to do this JUST to break local scope!
*/
function safeInclude($file) {
include($file);
}
Seriously, just read the comment.

Code: [Select]
final class Request {

private static
$data = false,
$path = '';

private static function set() {
self::$path = parse_url(cleanPath($_SERVER['REQUEST_URI']), PHP_URL_PATH);
if (strpos(self::$path, '..')) die('Hacking Attempt Detected, Aborting');
self::$path = substr(self::$path, strlen(ROOT_HTTP) - 1);
self::$data = (
empty(self::$path) ?
[ Settings::get('default_action') ] :
explode('/', self::$path)
);
foreach (self::$data as &$p) $p = urldecode($p);
} // Request::set

public static function value($index = 0) {
if (!self::$data) self::set();
return isset(self::$data[$index]) ? self::$data[$index] : false;
} // Request::value

public static function getPath() {
if (count(self::$data) == 0) self::set();
return self::$path;
} // Request::getPath

} // Request

Self initializing "static object", handles parsing $_SERVER['REQUEST_URI']. Notice that it strips out encoded/incorrect slashes and die's if it's a mismatch. Another die is performed if a ".." is included in the name so as to disallow up-tree hack attempts.

From there it just guts out the ROOT_HTTP (see below) for the basepath, explodes if appropraite, and then makes sure a urldecode is performed on each sub-chunk.

The value() routine is a getter, and getpath is handy occasionally.

Code: [Select]
final class Settings {

private static $privateData = [];

public static $publicData = [];
This one's a bit large so I'm going to just summarize by function name.

First up we have private and public data. The private ones should be for things you don't want normal code to even think about having access to changing.

Code: [Select]
public function loadFromIni(...$files)
Loads ini file data into $privateData or the appropriate public subsections and/or define(). Will overwrite existing private.

Code: [Select]
public static function get($name, $section = false)
Pulls private data as the priority, otherwise returns public, checking for sections or root as appropriate.

Code: [Select]
public static function set($value, $name, $section = false)
The setter can only set public data.

Code: [Select]
define(
'SCRIPT_PATH',
cleanPath(pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME))
);

SCRIPT_PATH is the directory path our script is in, but "cleaned" and having the name of the script ripped off it. Handy in a few cases, but mostly a prelude to:

Code: [Select]
define(
'ROOT_HTTP',
'/' . SCRIPT_PATH . (SCRIPT_PATH == '' ? '' : '/')
);

Which we "need" to prefix to local URI's for things like stylesheet LINK, script src="", and so forth.

... and that's the common.lib.php

I'll cover the sample /action/ next.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 15 Nov 2020, 11:45:33 am
/actions/static/static.startup.php -- a sample "process"

Startup functions are our "process", they take the already parsed user request and use it to either perform the requested action, or retrieve the requested data.

All action files should have a action_startup() function in them that returns an array of data. In this case our function:

Code: [Select]
if (!($page = Request::value(1))) {
$page = Request::value();
if (!$page || ($page == 'static')) $page = 'default';
}
if there's no second value in the URI (index 1) we see if there's a page that's the same as the request index 0. This allows for static pages to be called as /static/pageName or /pageName so long as page names don't match any actions. If this functionality is used, you may want to add a canonical <link> in the markup!

If it's not present either way, we use the 'default'.

We then set up the default call values:

Code: [Select]
$data = [
'contentFilePath' => 'actions/static/pages/' . $page . '/' . $page,
'pageName' => $page
];

$dataSources:
Code: [Select]
$dataSources = 0;

Is a counter of if a settings ini or a startup.php are loaded.

Code: [Select]
if (file_exists($fn = $data['contentFilePath'] . '.ini.php')) {
$dataSources++;
Settings::loadFromIni($fn);
}

We load any appropriate settings for the content into Settings

Code: [Select]
if (file_exists($fn = $data['contentFilePath'] . '.startup.php')) {
$dataSources++;
safeInclude($fn);
$data = array_merge(
$data,
static_startup()
);
}

and we run any startup for said page. Note that both can be done.

If neither ran:
Code: [Select]
if (!$dataSources) httpError(404);
Then we can assume a 404.

Otherwise:
Code: [Select]
return $data;

Now, once a database is involved we will be passing that around, so the declaration will change to:

Code: [Select]
function action_startup($db) {
So that it can pass the database to static_startup in any /actions/static/pages/pageName/pageName.php

Or in the case of other pages, use it itself to do database processing. Passing $db in this manner isolates its scope so that things which have ZERO blasted business accessing the database -- like the template -- have no access to it.

Remember, database connection in global scope is 100% hurr-durrz ermahgahd aherpaderp!

Now we have two different types of default pages setup, a "test" and a "default". Let's look at:

/actions/static/pages/default/default.ini.php

Code: [Select]
; <?php die(); // prevent direct calls just in case

currentPage "Home"

[meta]
keywords[name] = "keywords"
keywords[content] = "Default, Template, Poor, Man, Content, Management"

description[name] = "description"
description[content] = "Default Demo for Poor Man's Content Management"

The first line as already discussed prevents the .ini file from outputting anything if called directly via http just in case our rewriteRule goes awol.

We set the currentPage which is used to match the menu item in the template

Then some simple metadata as appropriate to the content.

The default page uses a .static file which is just static HTML content that will be loaded via readFile. Such statics are "ultra safe" because they cannot contain PHP.

The test on the other hand

/actions/static/pages/test/test.ini.php

Code: [Select]
; <?php die(); // prevent direct calls just in case

currentPage "Test"
noExtras true

Says "noExtras" to make the sidebars be hidden in the result, and it lacks any metadata.

It uses an actual:

/actions/static/pages/test/test.content.php

which defines our action_content that echo's out the result. The demo version just vomits up markup, but in practice action_content would be passed $data and the PHP would be used to call the template, gluing our $data to the markup as appropriate.

So a more proper version would go something like this:

Code: [Select]
function action_content($data) {

  // process and output the data here, calling the appropriate template functions.

} // action_content

In a nutshell, that's 90%+ of how squire is used to build a poor man's CMS and lays the groundwork for more complex systems.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Dave on 17 Nov 2020, 09:44:22 am
Early on in this thread GrumpyYoungMan asked
Quote
This code looks as it is something I could tweak to suit my needs - Am I free to do that and use your code?
I didn't see an answer but I have the same question. This looks perfect for a small side project I'm working on and would like to use it too,.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 17 Nov 2020, 10:05:57 am
@Dave,
There has been no objections to abusing the script on my site:


https://thisisatesttoseeifitworks.tk/deathshadow/static/info (https://thisisatesttoseeifitworks.tk/deathshadow/static/info)


As mentioned I am concerned at how closely knit the script is and updates will be very difficult. I sincerely hope I am wrong and looking forward to the conversion to a blog site.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 17 Nov 2020, 10:34:12 am
Early on in this thread GrumpyYoungMan asked
Quote
This code looks as it is something I could tweak to suit my needs - Am I free to do that and use your code?
I didn't see an answer but I have the same question. This looks perfect for a small side project I'm working on and would like to use it too,.
I thought I answered that, might have gotten lost in the other thread during the split.

I don't put code up online for people NOT to use. Consider the license -- for the time being -- as identical to that of SQLite... since to me, well... read the disclaimer/license I've released other software under:

Quote
Source Code © Jason M Knight and released to the public domain. If you are going to give something away, lands sake just GIVE IT AWAY!!!. Don't give me none of that dirty hippy "open source" nonsense!

Here's a tip: If someone starts running their mouth about "Freedom", only to then weigh it down with a licensing agreement larger than the founding documents of most nations; placing restrictions on what you can and cannot do with it by way of loopholes in contract law and legalese nobody but a business lawyer can decipher?

Well, does the term "snake oil" ring a bell?

In case you couldn't tell, not a fan of the FSF or the GPL. Stallman and his unwashed incels can **** right off.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 17 Nov 2020, 11:36:15 am
Thanks for the breakdown commentary. Very interested in seeing your Database implementation.

Questions:

1. What is Paladin you keep mentioning.
2. Can you please provide more info and simple code examples on function safeInclude showing the "problem" without it and how it solves that problem with it.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 17 Nov 2020, 03:11:53 pm
Squire3 is on my Github at https://github.com/benanamen/squire3 (https://github.com/benanamen/squire3)
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 17 Nov 2020, 08:05:13 pm
1. What is Paladin you keep mentioning.
Squire is NOT the system you see running, but a subsection of it ... the specific functions I believe I outlined. It is the closest thing I have to a framework, though it's really more of just a helper library.

Paladin is what it's called once it becomes a full CMS with database and the like.

Can you please provide more info and simple code examples on function safeInclude showing the "problem" without it and how it solves that problem with it.

The "problem" is that PHP bleeds scope like a pig. Wherever you do an include or require, it behaves as if the code you're including is right there in the code, in the same scope.

testInclude.php
Code: [Select]
<?php
echo $test;

test1.php
Code: [Select]
<?php
$test 
"something";
include(
'testInclude.php'); // outputs "something"

test2.php
Code: [Select]
<?php
$test 
"something";
function 
safeInclude($file) {
  include(
$file);
}
safeInclude('testInclude.php'); // throws an error, $test doesn't exist

because safeInclude is its own function with no global statement, it breaks scope. This means that we can use it to include files in places we don't want variables like $db to be blindly passed to them, limiting the number of places "bad things" can happen with code elevations.

Even though like all interpreted scripting source-distributed languages, PHP is an insecure wreck on that front, that doesn't mean we don't add multiple layers of code protections.

It's a royal pain in the ass and the biggest security hole in PHP that there's no PROPER library/unit inclusion, and that all file operations are allowed to blindly read/write source files. fopen/readfile/etc, etc, should all have been restricted from reading and writing .php or some other extension so that they can only be loaded as libs, with a mechanism JUST for library and perhaps another for just secure data.

Conceptually it's a bit like the "chicken and the echo" problem. Ever seen that one?

Code: [Select]
function test() { echo 'test.' }

echo 'This is a ' . test() . '<br>'; // outputs "test.This is a <br>"
echo 'This is a ', test(), '<br>'; // outputs "This is a test.<br>"

And people wonder why I favor comma delimits :D
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 17 Nov 2020, 09:24:34 pm
Ok, as this matures from Squire to Paladin, there's a few extra things to do first.

As a few folks have asked, we'll set up for language strings. These are common interface values or messages that we might want to internationalize.

Code: [Select]
final class Lang {

private static $cache = [];

public static function get($longName) {

if (substr($longName, 0, 1) !== '@') return $longName;

$splode = explode('_', substr($longName, 1), 2);
$name = $splode[0];
$module = count($splode) > 1 ? $splode[1] : 'common';
$lang = Settings::get('lang') ?: 'en';

if (!array_key_exists($module, self::$cache)) {
if (file_exists(
$fn = 'lang/' . $lang . '/' . $module . '/' . $module .  '.ini.php'
)) self::$cache[$module] = parse_ini_file($fn);
else self::$cache[$module] = [];
}

if (
array_key_exists($name, self::$cache[$module])
) return self::$cache[$module][$name];

if (file_exists(
$fn = 'lang/' . $lang . '/' . $module . '/' . $name . '.txt'
)) return self::$cache[$module][$name] = file_get_contents($fn);

error_log(
'Paladin Error -- Lang::get, key "' . $name .
'" not found in module "' . $module
);

return '<strong style="color:red; font-weight:bold;">LANG[' . $longName . ']</strong>';

} // Lang::__get

} // Lang

The format for calliing Lang would go something like this:

Lang::get('@title_loginModal');

If the global language is set to "en" it will return the name before the underscore in /lang/en/loginModal/loginModal.ini.php, or the contents of the text file /lang/en/loginModal/title.txt

Said values are cached should you decide to use them twice. An example .ini goes something like this:

Code: [Select]
; <?php die();

title "Log In"
username "Username"
password "Password"
submit "Submit"

If you wanted to add french to the system:

/lang/fr/loginMOdal/loginModal.ini.php
Code: [Select]
; <?php die();

title "S'identifier"
username "Nom d'utilisateur"
password "Mot de passe"
submit "Soumettre"

So anyplace you have UI elements you want to internationalize, you use Lang:: to pull the corresponding string.

Be aware that:

1) if a language string is not found, a styled STRONG tag is returned of the name. Normally I rail against the use of style="" in all but a handful of corner cases. Hello Mr. Corner Case.

2) Should you feed it a string without the @, it will return the normal string. This can be handy during prototyping.

3) if you @ but without the underscore, "common" will be used instead. Hence "@test" would be the same as @test_common

Next on deck is "Bomb". It's a static function that will wrap all our different throw, loading their code only as needed. Basically httpError gets folded into this as well as the native system. Think of Bomb as being like a "die" that loads the template and logs the error.

Code: [Select]
/*
Bombs are fatal errors, execution will end after message
is logged and displayed.
*/

final class Bomb {

public static function http($code) {
include('fragments/httpError.php');
} // Bomb::http

public static function paladin($title, $desc) {
include('fragments/paladinError.php');
} // Bomb::paladin

} // Bomb

This way we only have a single static polluting the namespace.

httpError you already have, paladinError looks similar.

/fragments/paladinError.php
Code: [Select]
<?php
/*
ASSUMES
$title
$desc
*/

Settings::set('Paladin System Error''pageTitle');
Settings::set(true'noExtras');

template_header();

error_log('Paladin Error - ' $title ' - ' $desc);

echo 
'
<section class="httpError">
<div>
<h2>'
Lang::get('@title_errors'), '</h2>
<p>
'
Lang::get('@systemError_errors'), '
</p><p>
'
Lang::get('@errorHasBeenLogged_errors'), '
</p>
</div>
</section>'
;

template_footer();

die();

Note that the error is NOT shown client side, and is logged instead. Bomb should be used for error conditions that could bleed information client-side hackers could exploit, like a database connection failure.

The corresponding language file being:

/lang/en/errors/errors.ini.php
Code: [Select]
; <?php die();

title "Paladin Error"
systemError "A system error occurred. Please try again. If the problem persists please contact the administrator."
errorHasBeenLogged "This error has been logged"

It's also time to lay out the database structures. For now we'll do users, user_permissions,

For users let's go basic:

Code: [Select]
CREATE TABLE users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128) UNIQUE,
username VARCHAR(64) UNIQUE,
password VARCHAR(64),
register_email VARCHAR(320),
contact_email VARCHAR(320),
created DATETIME DEFAULT CURRENT_TIMESTAMP
last_access DATETIME DEFAULT CURRENT_TIMESTAMP
INDEX (name, username, last_access)
)

Name being the "display name" used in output, which can be different from the login username. Password is big enough to accept 512 bit ciphers, and of course some standard timestamps.

For user permissions:

Code: [Select]
CREATE TABLE user_permissions (
id BIGINT,
permission VARCHAR(127),
filter TINYINT DEFAULT 0
INDEX (id, permission)
)

Permission is the text name of the permission, such as "Can Write Blogs" or "Can Edit Users". Filter is one of -1, 0, or 1, representing prevent, no, and yes respectively.

When/if we get into user groups, they too will have permissions (groups_permissions) that will have filters. The filters will be binary "and" together. To test if a user has the permission, we'll simply "$user->hasPermission('Can Tell Users to Sod Off') > 0"

For those confused, "prevent"  means the user is never allowed to have the permission, regardless of what other user groups or even the user's own permissions say.

Ok, the next step is to get a setup routine going. The setup will work in stages, use sessions and hashes to verify installation steps as sent client-side, be password locked off a value in the user.config.ini.php, etc, etc, etc...

I always build a proper installer at the start instead of dicking around in phpMyAdmin or at the command line. You're going to need it anyways, so just DO IT!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 17 Nov 2020, 09:50:11 pm
Thanks for clarifying with code on the safeInclude function.

Quote
Wherever you do an include or require, it behaves as if the code you're including is right there in the code, in the same scope.

That is the exact behavior I want to separate parts. I would like to see use cases where I would actually need the safeInclude function.

Example

<?php

include 'header.php';
include 'nav.php';
include 'content.php';
include 'footer.php';


Quote
the "chicken and the echo" problem

This is interesting that it works like it does. Can you explain why it does what it does?

EDIT: Ok, I see why this "problem" exists. In the function, you are echoing the text "test" instead of returning it. If you return the text then all the examples work as they should.

The periods are concatenation. The commas are argument separators just like in functions. The arguments are written to the output in the same order as they are passed in.

With your first example, the period has precedence so the function right after it is run first, then everything else is output.

I would have to call this a good example of bad programming.

Providing arguments for echo is faster, so you still have a win there.

This works in both examples using return:
Code: [Select]
function test() { return 'test.'; }

echo 'This is a ' . test() . '<br>'; // outputs "This is a test.<br>"
echo 'This is a ', test(), '<br>';   // outputs "This is a test.<br>"


Your example could very well have been written like this for more clarification of operator precedence. The output is exactly the same.
Code: [Select]
echo 'This is a <br>' . test() ; // outputs "test.This is a <br>"
This "problem" is simply about operator precedence and echoing a function output instead of returning it.



Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 17 Nov 2020, 11:40:45 pm

Conceptually it's a bit like the "chicken and the echo" problem. Ever seen that one?

Code: [Select]
function test() { echo 'test.' }

echo 'This is a ' . test() . '<br>'; // outputs "test.This is a <br>"
echo 'This is a ', test(), '<br>'; // outputs "This is a test.<br>"

And people wonder why I favor comma delimits :D

This appears to be legacy code and not taking advantage of PHP 7.0 Declare((strict_types=1);

When using declare(strict_types=1); an error will be thrown because function test(); is not a string. The type can be found using gettype();

Without using strict_types=1 PHP will not bother checking types and no errors will be thrown. Type juggling  will try guessing the type.

Why is strict_types=1 never used in this current project?

Please note that I am currently unable to test because I am in the process of resurrecting  my OS :(

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 18 Nov 2020, 12:04:25 am
Why is strict_types=1 never used in this current project?
Because it's mostly pedantic bullshit and shoe-horning of programming concepts that have ZERO business in an interpreted scripting source-distributed language?

It offers ZERO legitimate benefits, and in many ways defeats the entire reason PHP is superior to other languages when it comes to gluing data to markup. Type insensitivity may be a bitch for logic, but it's a blessing when dealing with output.

And used "properly" that's the most PHP should be doing. Processing the user request, interacting with the database, and outputting the results by gluing data to markup. It excels at this and adding strict typecasting pisses on that.

FFS if people want it to behave like C++ or C#, why the **** aren't they just using C++ or C#?!?

Seriously, if I wanted to use a language that behaved that way, I'd be using Ada or even FPC. I'm not, I'm using PHP, so I expect it to behave like an interpreted scripting language should.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 18 Nov 2020, 12:16:03 am
When using declare(strict_types=1); an error will be thrown because function test(); is not a string.

NO! It is because Jason forgot a semi-colon at the end of the echo. NOTHING whatsoever to do with strict types.

I am surprised after all this time you STILL dont understand strict_types.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 18 Nov 2020, 12:20:43 am
Quote
Wherever you do an include or require, it behaves as if the code you're including is right there in the code, in the same scope.

Followup...

This is the EXACT purpose of include/require. Per the manual..
Quote
The include statement includes and evaluates the specified file.

Quote
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward.

That pretty much blows out your claim that an include shouldn't output anything.

https://www.php.net/manual/en/function.include.php (https://www.php.net/manual/en/function.include.php)

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 18 Nov 2020, 12:50:50 am
That is the exact behavior I want to separate parts. I would like to see use cases where I would actually need the safeInclude function.

Example

<?php

include 'header.php';
include 'nav.php';
include 'content.php';
include 'footer.php';
That example is NOT something I would do, since it looks like "blind includes". Do those include contain functions, or are they spitting out markup directly without functions?

Really there's NO reason for them to be separate includes, and I would suspect you've got ZERO scope isolation.

Hmm... the database connection in the next release of this is a very good usage case. Let's take some features from main() which replaces the IIFE in index. (see previous post about the new index.php)

It connects to the DB
Code: [Select]
$db = new Database($dsn, $username, $password, $options);

Later on the same function loads the content outputter:

Code: [Select]

if (file_exists($fn = $data['contentFilePath'] . '.content.php')) {
safeInclude($fn);
action_content($data);
}

That PHP file has ZERO business having access to the database handler. None. Nada, Zip, Zilch. Given how easy code appendages are (thanks to the F***wit ability of PHP to fopen source files) and how often they are a "non-destructive avenue of attack", restricting access to the gooey bits and adding re-use prevention is essential to at least make them work harder for it.

Since any idiot can fopen "a", modifying the existing code or supplanting it takes a bit more work. It's not a great answer, but with PHP's "insecure by design" methodology, we do what we can do.

EDIT: Ok, I see why this "problem" exists. In the function, you are echoing the text "test" instead of returning it. If you return the text then all the examples work as they should.

The periods are concatenation. The commas are argument separators just like in functions. The arguments are written to the output in the same order as they are passed in.

With your first example, the period has precedence so the function right after it is run first, then everything else is output.

I would have to call this a good example of bad programming.
It's not always. In fact if you understand the underlying mechanism if all you're going to do is echo the result, it can be more efficient on memory use since you're not expanding the stack or lobbing the result onto the heap.

But it's a matter of do you want to be a pedantic ass willing to slop out a massive memory footprint for the name of some esoteric bullshit, or do you want efficient code. Though again, I suspect that's my inner machine language coder talking. There's a  LOT of things high level language dev's say that make me go "dafuq u say?"

Generally though yes, it's a construct one would not use without very good reason. It's more of a mental exercise to illustrate why string addition (concatenation my ass) on echo is an inefficient construct, painfully so if you look at memory usage. It's not "operator precedence" apart from the fact the string HAS to be COMPLETELY built before it can be passed to echo!

When you use a string addition the ENTIRE string has to be built in memory before it can be passed to the result. Be that result a variable, a function, or a language construct like echo.

That means you have to malloc a "guess' as to how big the result is going to be, it means you might have to "grow" using pointers or reallocate to a new larger memory pointer (the latter wasting time copying your existing values again and leading to memory fragmentation). EVERYTHING has to be copied into this new result before it can be passed along.

Whereas if you comma delimit echo, static pointers to the static strings and dynamic pointers to the variables can just be passed in sequence, requiring none of the mental masturbation and memory thrashing idiocy that string addition brings to the table. Inf act, this is why most of the string heavy string-based string processing "template" systems like Smarty are bloated inefficient crap, no matter how much it mollycoddles "front end developers" who to be frank, don't know enough about the back end to be front-ending jack!

About two years ago I had a client where their site was killing their high end hosting despite traffic numbers a cheap VPS could have handled. It was constantly choking out on RAM, and the reason was obvious to me, but invisible to most. String addition.

They had constructed their PHP output to be one giant ternary operation as a single string added echo. The result was that their bloated 240k of markup was taking a megabyte or more to process. Now, a megabyte might seem like piss in a bucket in the age of gigabytes of RAM... but that's a megabyte of string processing, multiple stack/heap grows, endless copying of that megabyte of strings around, and you multiply that against a hundred thousand requests an hour, and we're talking terrabytes of memory thrashing over that time period.

Just switching it to separate statements and comma delimited echo's dropped the memory footprint by a factor of four and processing time by 3. Of course once I replaced their nutjob 240k of bloat with the 28k needed to do the job, they were able to switch from a big fancy expensive dedicated server to a $20/mo VPS.

And in that way, calling a function to output something from inside an echo can in fact result in lower memory use. I mean in practice it's NO different (given how null is echo'd) from:

echo 'This is a ';
test();
echo '<br>';

It's just a cleaner simpler syntax. It can also be a handy construct in template separation.

Code: [Select]
echo test($id, $db) ? '<i class="fas fa-lock-open"></i>' : '<i class="fas fa-lock"></i>';
Code: [Select]
function test($id, $db) {
  $stmt = $db->prepare('SELECT text, statusCode FROM status WHERE id = ?');
  $stmt->execute([$id]);
  if ($row = $stmt->fetch()) {
    echo $row['text'];
    return $statusCode > 0;
  }
  echo sprintf(Lang::get('failed_status'), $id);
  return false;
} // test

Test may echo any of a dozen different text values, but it returns true or false so we can show the correct icon SEPARATELY from the content text. That way the template can set the icon without care for what text is echo'd out by the function.

Consider it akin to how you can leverage boolean false with === on a return value vs. string where a empty string is a valid value, or multi-handle parameter types (like echo does).
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 18 Nov 2020, 12:54:20 am
That pretty much blows out your claim that an include shouldn't output anything.
The function include does indeed do that, but that has NOTHING to do with my statement. What I'm bemoaning is the LACK of a proper include mechanism for libraries BECAUSE include works exactly the way your saying.

We have no proper equivalent of a "unit" or a "dll" or any other SECURE interface, so we're stuck trying to fake it with include or require.

YES that's how include works, and that's the flipping problem! If you call an include file via http directly, it ends up spewing out crap. If it is blindly included it just runs...

Wrapping everything in functions or classes prevents that. It's a mechanism of protection that PHP's dipshit insecure 1970's style includes fails to provide. Avoiding the instant execution behavior is what we should be trying to avoid!

Seriously, there are times PHP reminds me way too much of everything that was wrong with UCSD Pascal.

A WELL WRITTEN include shouldn't output dick... it's a shame php's include() is too stupid to provide for that.

Part of why their dicking around adding idiocy like strict_types pisses me off when there are gaping security issues that shouldn't be hard to fix. There are bigger fish to fry...
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 18 Nov 2020, 02:57:28 am
When using declare(strict_types=1); an error will be thrown because function test(); is not a string.

NO! It is because Jason forgot a semi-colon at the end of the echo. NOTHING whatsoever to do with strict types.

I am surprised after all this time you STILL dont understand strict_types.


I did not test the script and assumed that the function would return a  NULL that strict_types would not change the NULL to a string.  I prefer to test scripts and unfortunately still having problems with my operating system which needs reinstalling...

I do like your GitHub Repository and looking forward to updates.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 18 Nov 2020, 10:32:01 am
I did not test the script and assumed that the function would return a  NULL that strict_types would not change the NULL to a string.

Echo doesn't care. Many PHP functions RELY on non-strict type juggling, which is one of the reasons strict typecasting in PHP is a complexity mismatch.

In fact, the fact that echo doesn't care what type of variable you feed it is part and parcel of why PHP is better at outputting markup than most other languages. AND part of why I say that running a "template system" like smarty atop PHP is ignorant incompetent trash.

... and remember that's coming from someone well versed in Ada, one of the most strictly typecast languages out there.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 18 Nov 2020, 11:34:20 am
Quote
That example is NOT something I would do, since it looks like "blind includes". Do those include contain functions, or are they spitting out markup directly without functions?

In the basic example I showed we are pretty much talking about straight HTML "templates" with perhaps minimal php for a foreach loop such as in the case of a Dropdown Select or looping through a database result.

Quote
Really there's NO reason for them to be separate includes

Sure there is! How about "Code Separation"? Instead of having one page jumbled with all that code you now have it broken down into separate "templates" which can easily be re-used anywhere else with just an include and the calling page is very clean and simple. Very easy to debug or make changes to any of the parts.

Quote
I would suspect you've got ZERO scope isolation.

In this case, there is no reason whatsoever to have "scope isolation". What you want is just the opposite which is the exact purpose as stated earlier, "inherit the variable scope of the line on which the include occurs."

You have gone into great detail on echo and why commas are better. There is no argument there. Nevertheless, I think it is safe to say using commas over a period is a micro-optimization.

So with the great concern you have over even just an extra meg of memory usage, why are you using functions AND an echo to output what is pretty much 100% HTML? There is obviously more overhead to calling a function and then making Php parse through a bunch of HTML looking for real Php code. I asked this earlier but you didn't answer.

Edit: Just saw a previous post where you explain your complaint about includes. I understand where you are coming from now.

Edit-Edit:
Quote
We have no proper equivalent of a "unit" or a "dll" or any other SECURE interface, so we're stuck trying to fake it with include or require.

I was going to say... but you answered it yourself.

Quote
Wrapping everything in functions or classes prevents that.

If you are coding in OOP then this is a non-issue just like you stated, "prevents that".

Quote
If you call an include file via http directly, it ends up spewing out crap.

Your includes should not even be publicly accessible. They "should" be above the web root. Simple Architecture and a non problem.

In the case where a user does not have access above webroot (time for a new host) a simple .htaccess "Allow None" in the folder blocks access. An additional method could use code like such in the includes which are called by "one index to rull them all" where SECURE_PAGE is defined.

Code: [Select]
if (!defined('SECURE_PAGE'))
{
    die('<h1>Direct File Access Prohibited</h1>');
}
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 18 Nov 2020, 04:36:57 pm
In the basic example I showed we are pretty much talking about straight HTML "templates"
Which is not something I would do in the case of what the files listed appear to be for. Ever.

with perhaps minimal php for a foreach loop such as in the case of a Dropdown Select or looping through a database result.
And the current menu item, and the current langauge, and the keywords/description meta, and the pagetitle half of the <titlle>, and the menu items if they are dynamic, and any page specific scripts/stylesheets, and any control structures such as columns or not...

Sure there is! How about "Code Separation"? Instead of having one page jumbled with all that code you now have it broken down into separate "templates" which can easily be re-used anywhere else with just an include and the calling page is very clean and simple.
Which if implementing one index means one template. These are all things that should be the same on ALL pages, so why are you splitting them up into separate files?

Or are you going to have separate instances of the page structure outside of <main>? Aka not something a CMS has any legitimate reason to do unless your intent is to piss off users?

Very easy to debug or make changes to any of the parts.
A nonsensical claim, as if line numbers and files are hard to backtrace? Or knowing your markup and functions is any different from files?

In this case, there is no reason whatsoever to have "scope isolation". What you want is just the opposite which is the exact purpose as stated earlier, "inherit the variable scope of the line on which the include occurs."
Not even sure what you mean by that, since there's TONS of reasons in mine to have scope isolation, and honestly there SHOULD BE in yours once you get a DB installed.

Again, I just think we're light-years apart in how we implement things, and why.

You have gone into great detail on echo and why commas are better. There is no argument there. Nevertheless, I think it is safe to say using commas over a period is a micro-optimization.
It's not a micro-optimization when you look at the memory footprint and work involved for the CPU. We're literally talking at a lower level the difference between simply calling echo's sub-pieces via pointer in turn, a flat parameter loop that doesn't have to copy anything or allocate any memory, vs having to allocate a wild guess of result size, copy first part, copy second part, copy third part, copy fourth part, HOPING we don't have to grow the result, probably growing the result needing an entire copy of the whole thing or creation of a multipart pointer structure, copy, copy, copy some more, THEN send that one part to the echo, THEN have to deal with garbage collection later on.

That's not micro-optimization. Next you'll be quoting Knuth out of context.

So with the great concern you have over even just an extra meg of memory usage
That can easily multiply into TB depending on traffic...

why are you using functions AND an echo to output what is pretty much 100% HTML? There is obviously more overhead to calling a function and then making Php parse through a bunch of HTML looking for real Php code. I asked this earlier but you didn't answer.
Because I WANT scope isolation? Because some structures I include might be re-used? Because one function call isn't going to break the bank outside the loop or waste a ton of memory because static strings are static strings inside or outside the code? In fact putting them into what's likely the data segment instead of the code segment (assuming PHP has similar structures) might result in better caching models?

Because I hate seeing <?php ?> all over the damned code and prefer one <?php per file where practical?

(seriously, I find endless pointless <?php ?> all over the code utterly illegible trash)

Your includes should not even be publicly accessible. They "should" be above the web root. Simple Architecture and a non problem.
Except not all hosting plans allow you access to anything above the web root via FTP hobbiling the ability to install codebases that pull that stunt. Not all hosting plans have the same structure above the web root meaning you could have directory naming conflicts. Not all hosting plans give PHP permission to access anything above the web root meaning you cannot even include from there.

Putting stuff about the web root is a stupid stunt that limits the potential audience and hosting targets! Don't even get me started about how it means using up-tree links (stupid) or absolute local links (even ***ing dumber) that are unreliable and hobble portability.

One of the earliest lessons I learned about writing software for the web that's as true today as it was in decades past. IF you need to "../" or absolute path the local filesystem, you're doing something WRONG!

Crapping stuff in above the web root is NOT a good practice. Pretty damned far from it!

In the case where a user does not have access above webroot (time for a new host) a simple .htaccess
Assuming one is on apache... and that such access is even enabled.

An additional method could use code like such in the includes which are called by "one index to rull them all" where SECURE_PAGE is defined.
Which is fine when things are going honky-dory... and utter trash should that mechanism break down, hence the multiple layers.

"One index to rule them all" does NOT mean one ring security.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 18 Nov 2020, 06:38:04 pm
Looking forward to seeing your database implementation when you can get to it.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 19 Nov 2020, 11:46:39 pm
Insomnia set in (dangerous with my non-24) so I figured I'd pluck away at this.

I'm rewriting Bomb yet again:

Code: [Select]
final class Bomb {

public static function http($code) {
include('fragments/httpError.php');
} // Bomb::http

public static function paladin($data, $printfData = false) {
include('fragments/paladinError.php');
} // Bomb::paladin

} // Bomb

Not much change there, right? Well, it's all in the calls.  Oh note I don't "safeinclude' these because the parent method does the same thing. (as @benanamen said, if you're working with objects...)

/fragments/httpError.php
Code: [Select]
<?php
/*
ASSUMES
$code == HTTP error code number
*/

if (empty($code)) $code 501;

$langText Lang::get('@' $code '_httpErrors');
if (
substr($langText014) === '<strong style='
$langText Lang::get('@unknown_httpErrors');

$codeText $code ' - ' $langText;

http_response_code($code);
Settings::set($codeText'pageTitle');
Settings::set(true'noExtras');

template_header();

template_section(
'httpError',
$codeText
);

echo 
'
<p>
'
sprintf(
Lang::get('@requestNotServed_httpErrors'), 
htmlspecialchars($_SERVER['REQUEST_URI'])
), '
</p>'
;

template_sectionFooter();

template_footer();

die();

Uses /language/twoLetterCode/$code.txt for the titles and descriptions. Note that I use sprintf to plug in the URI. That's the closest I ever come to string templates.

Now Paladin errors on the other hand...

Code: [Select]
<?php
/*
ASSUMES
$data
[ $printFdata ]

if $data is array, assume each is a Lang lookup
Otherwise is prefix for constructed Lang lookup

The optional $printFdata is an Array that will be plugged
into the language string via vsprintf.


*/

Settings::set(Lang::get('paladinSystemError'), 'pageTitle');
Settings::set(true'noExtras');

template_header();

if (
is_array($data)) {
$title Lang::get($data[0]);
$desc Lang::get($data[1]);
} else {
$title Lang::get('@' $data 'Title_errors');
$desc Lang::get('@' $data 'Desc_errors');
}

if (
$printfData$desc vsprintf($desc$printfData);

error_log(Lang::get('@title_errors') . ' - ' $title ' - ' $desc);

template_section(
'paladin_error',
Lang::get('@title_errors')
);

echo 
'
<p>
'
Lang::get('@systemError_errors'), '
</p><p>
'
Lang::get('@errorHasBeenLogged_errors'), '
</p>'
;

template_sectionFooter();

template_footer();

die();

Allows for quick system level errors like "userNotFound" to pull the title and data strings automagically or to pass an array containing their individual names/strings values.

Also rewritten to properly use the template sections so all these output fragments do contain is the content.

With error handling in place we can start in on the database handler.

/database/mysql/mysql.database.php

Each SQL engine type can have its own Database object in a sqlname.database.php file. Each SQL engine directory will contain a /queries/ directory containing "named queries".

"Named queries" is an old practice from the late '80's and early '90's that I don't understand why it was dropped. The idea is that instead of passing a query right there in the code, you create semantic names for what the query is, then dynamically load them (and caching them) as needed.

This has numerous advantages.

1) the code's easier to deal with without the giant queries in the way.

2) It makes cross-engine development simpler. Yes, for now I'm only doing mysql, but anyone wants to add other engines the hooks are all present ahead of time!

3) If we extend PDO and overload ->exec, ->prepare, and ->query we can prevent people from manually entering queries. This makes life a little harder for hackers who gain code elevations as SHOULD we bleed $db into the scope, they're restricted to the named queries.

4) Overloading those methods also forces developers coming in to use the named query system, preventing them from making code that can't be ported to other engines.

5) we can use authorization to restrict what actions can and cannot call what queries. For example our "/action/setup" installer queries we probably don't want "/user/profile" gaining access to, so we can put a "setup.auth.ini.php" file in that says "ALL = 0" saying to block everything except setup... or you could authorize a bunch of them.

The disadvantages?

1) You can't just blindly make a query string.

2) Things like variable numbers of placeholders is hard to implement safely.

In my named queries some things you can't inject via placeholders, and/or might need to be set even when executing. To that end I implement bang-tag style inserts for things like table prefixes, table names, etc.

For example:

Code: [Select]
tableExists = "
SHOW tables
LIKE '!PREFIX!!TABLE!'
"
rowCount = "
SELECT COUNT(*)
FROM !PREFIX!!TABLE!
"

or

Code: [Select]
users = "
CREATE TABLE !PREFIX!users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(127) UNIQUE,
username VARCHAR(63) UNIQUE,
password VARCHAR(255),
register_email VARCHAR(320),
contact_email VARCHAR(320),
created DATETIME DEFAULT CURRENT_TIMESTAMP,
last_access DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX (name, username, last_access)
)
"

Or even: (this one is for User::touch... which is done in private. You just grab 'em by the timestamp. When you're famous they let you get away with that.

Code: [Select]
UPDATE !PREFIX!users
SET last_access = CURRENT_TIMESTAMP
WHERE id = ?

Now, to help secure things there are going to be some standard practices in how SQL stuff should be named.

1) No uppercase in table or variable names.

2) All SQL statements/properties should be UPPERCASE only.

3) all table names should have !PREFIX! before them to plug that in automagically.

4) new statements should go on new lines. No slopping it all onto single lines unless it's VERY basic.

Alright, probably close to the post size limit, so I'll post the code for the PDO extension in the next post.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 20 Nov 2020, 12:19:00 am
Here it is:

Code: [Select]
final class Database extends PDO {

private
$authorizations = [],
$queries = [];

// START PUBLIC OVERLOADS

public function __construct(
$dsn,
$username,
$password,
$options = [],
$tablePrefix = false
) {

if (defined('DB_CONSTRUCTED')) Bomb::paladin(
'HACKING ATTEMPT DETECTED',
'Attempt to create "Database" more than once'
);
define('DB_CONSTRUCTED', 1);

$options[PDO::ATTR_STATEMENT_CLASS] = [ 'DatabaseStatement', [ $this ] ];

try {
parent::__construct($dsn, $username, $password, $options);
} catch (PDOException $e) {
Bomb::paladin('Database Connection Error', $e );
}

define('DB_TABLE_PREFIX', $tablePrefix ? $tablePrefix . '_' : '');
define('DB_QUERY_DIR', 'database/' . SQL_ENGINE . '/queries/');

} // Database::__construct

public function exec($name, $module = 'common', $tableName = false) {
try {
$stmt = parent::exec($this->namedQuery($name, $module, $tableName));
} catch (PDOException $e) {
Bomb::paladin(
'dbExecError', [ $name, $module, $e->getMessage() ]
);
}
if ($this->errorCode() > 0) Bomb::paladin(
'dbExecError', [ $name, $module, $stmt->errorInfo()[2] ]
);
return $stmt;
} // Database::exec

public function prepare($name, $module = 'common', $tableName = false) {
try {
$stmt = parent::prepare($this->namedQuery($name, $module, $tableName));
} catch (PDOException $e) {
Bomb::paladin(
'dbExecError', [ $name, $module, $e->getMessage() ]
);
}
if ($this->errorCode() > 0) Bomb::paladin(
'dbPrepareError', [ $name, $module, $stmt->errorInfo()[2] ]
);
return $stmt;
} // Database::prepare

public function query($name, $module = 'common', $tableName = false) {
try {
$stmt = parent::query($this->namedQuery($name, $module, $tableName));
} catch (PDOException $e) {
Bomb::paladin(
'dbExecError', [ $name, $module, $e->getMessage() ]
);
}
if ($this->errorCode() > 0) Bomb::paladin(
'dbQueryError', [ $name, $module, $stmt->errorInfo()[2] ]
);
return $stmt;
} // Database::query

// END PUBLIC OVERLOADS

// START PUBLIC EXTENSIONS

public function prepExec($data = [], $name, $module = 'common', $tableName = false) {
$stmt = $this->prepare($name, $module, $tableName);
$stmt->execute($data);
return $stmt;
} // Database::prepExec

public function rowCount($tableName) {
$stmt = $this->query('rowCount', 'common', $tableName);
return $result->fetchColumn();
} // Database::rowCount

public function safeName($name) {
return $name = preg_replace('/[^a-z0-9_]/', '', $name);
} // Database::safeName

public function tableExists($name) {
$stmt = $this->query('tableExists', 'common', $name);
return $stmt->fetch();
} // Database::tableExists

// END PUBLIC EXTENSIONS

// START PRIVATE EXTENSIONS

private function namedQuery($name, $module = "common", $tableName = false) {

if (!$this->auth($name, $module)) Bomb::paladin(
'unauthorizedQuery', [ $name, $module ]
);

if (!array_key_exists($module, $this->queries)) {
$this->queries[$module] = file_exists(
$fn = DB_QUERY_DIR . $module . '/' . $module . '.queries.ini.php'
) ?  parse_ini_file($fn) : [];
}

if (!array_key_exists($name, $this->queries[$module])) {
if (file_exists(
$fn = DB_QUERY_DIR . $module . '/' . $module . '.' . $name . '.sql'
)) $this->queries[$module][$name] = file_get_contents($fn);
else Bomb::paladin('queryNotFound', [ $name, $module ]);
}

$query = str_replace(
'!PREFIX!',
DB_TABLE_PREFIX,
$this->queries[$module][$name]
);

if ($tableName) {
if ($this->safeName($name)) {
$query = str_replace('!TABLE!', $tableName, $query);
} else Bomb::paladin('invalidTableName', [ $tableName ]);
}

return $query;

} // Database::namedQuery

private function auth($name, $module) {

if ($module === 'common') return true;

if (!array_key_exists($module, $this->authorizations)) {
if (file_exists(
$fn = DB_QUERY_DIR . $module . '/' . $module . '.auth.ini.php'
)) $this->authorizations[$module] = parse_ini_file($fn);
else return true;
}

if (
array_key_exists('ALL', $this->authorizations[$module]) &&
$this->authorizations[$module]['ALL'] === 0
) return $module === ACTION;
)
return (
array_key_exists($name, $this->authorizations[$module]) &&
$this->authorizations[$module][$name] !== 0
);

} // Database::auth

// END PUBLIC EXTENSIONS

} // Database

I extend PDO rather than make a new class, because we want to prevent conventional calls as cleanly as possible.

We have two private variables for caching. $authorizations is for the auth check, $queries is for query strings.

We overload the contstructor to add our auto table prefix support, to automatically add our try/catch on the parent to Bomb if need be, to prevent Database from being initialized more than once (which should NOT be done), and to set up DEFINE of non-security related immutables. As the old joke goes use define a lot. NO, A LOT!!!

Let's get into some of the tricky stuff.

Code: [Select]
$options[PDO::ATTR_STATEMENT_CLASS] = [ 'DatabaseStatement', [ $this ] ];

This overrides the default PDOStatement to use our own extension of it. I create this extension so that

1) PDOSTATEMENT::$pdo is PRIVATE!

2) We can "lock" statements to prevent further "execute". This is handy if we end up passing the PDOStatement to the template logic to reduce the memory footprint that ->fetchAll can induce.

It's amazing how many systems go bits-up on that

DatabaseStatement going like this:

Code: [Select]
class DatabaseStatement extends PDOStatement {

private
$pdo,
$locked = false;

protected final function __construct($pdo) {
$this->pdo = $pdo;
} // DatabaseStatement:__construct

public final function execute($input_parameters = Null) {
if ($this->locked) return false;
return parent::execute($input_parameters);
} // DatabaseStatement::execute

public final function lock() {
$this->locked = true;
}

} // DatabaseStatement

Pretty simple stuff. Why they don't offer locking out of box is beyond me. Just begs for a accidental re-use.

I'm gonna go through "Database"'s methods out of code order, as they're ordered by public/private and then by name... not by functionality/dependency. I prefer the latter, but this isn't about me.

PRIVATE EXTENSIONS

private function namedQuery($name, $module = "common", $tableName = false)

This pulls our named queries from the /sql/sqlengine/queries directory. First we do an authorization check, and if that fails we bomb. (we'll cover auth next).

If the module is not in the $this->queries cache we see if a module .queries.ini.php file exists, and load it. If it's not set and the file doesn't exist, make it an empty array.

Next if the query name doesn't exist in the cache, we see if there's a .sql file specific to that one query. If so, load it. Otherwise bomb as the named query doesn't exist.

We get past that we plug in our !PREFIX! and !TABLE! bombing if $tableName contains anything other than [a-z0-9)]. Again, notice no uppercase allowed!

We get past that without bombing, $query is ready to be returned to the caller.

private function auth($name, $module)

The query authorization function for checking if ACTION is allowed isn't too tricky. "common" are always authorized so short-circuit out for those first.

If the module doesn't exist, see if there's a module file and load it. If there is no authorization file, we'll assume AUTHORIZED.

If "ALL" is set and is zero, it means nothing is authorized except ACTION.

Finally if the $name is set and it's non-zero, return true.

PUBLIC EXTENSIONS

public function prepExec($data = [], $name, $module = 'common', $tableName = false)

Simple function to do a prepare and an exec in one pass.

public function rowCount($tableName)

Can you guess what this does? Tells you how many tables a row has.

public function safeName($name)

Returns boolean if any characers other than a-z0-9_ are present in the passed string.

public function tableExists($name)

Again, aren't good naming conventions a blessing?

PUBLIC OVERLOADS


public function exec($name, $module = 'common', $tableName = false)
public function prepare($name, $module = 'common', $tableName = false)
public function query($name, $module = 'common', $tableName = false)


Kissing cousins, they all just call ->namedQuery to get the proper query string, and Bombs if there's an error. They work for now, but could really use some DRY loving.

... and that's basically the database code. Untested, might have typo's or flubs as this is a clean-room re implementation of what I usually do. Case testing and creating the installer go hand in hand... because there's noplace better to test it than with real operations.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 20 Nov 2020, 01:07:33 am
... and here's that DRY loving.

Code: [Select]
private function dryStatement($method, $args) {
try {
$stmt = parent::$method($this->namedQuery($args[0], $args[1], $args[2]));
} catch (PDOException $e) {
$errorMessage = $e->getMessage();
}
if ($stmt->errorCode() > 0) $errorMessage = $stmt->errorInfo()[2];
if (empty($errorMessage)) return $stmt;
Bomb::paladin(
'db' . ucFirst($method) . 'Error',
[ $args[0], $args[1], $errorMessage ]
);
} // Database::dryStatement

Reducing them down to:

Code: [Select]
public function exec($name, $module = 'common', $tableName = false) {
return $this->dryStatement('exec', func_get_args());
} // Database::exec

public function prepare($name, $module = 'common', $tableName = false) {
return $this->dryStatement('prepare', func_get_args());
} // Database::prepare

public function query($name, $module = 'common', $tableName = false) {
return $this->dryStatement('query', func_get_args());
} // Database::query
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 20 Nov 2020, 03:43:16 am
Can you also add a basic user registration system?

And if you are turning into a very basic CMS system - can the pages be generated dynamically via a database?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 20 Nov 2020, 09:23:52 am
Can you also add a basic user registration system?

And if you are turning into a very basic CMS system - can the pages be generated dynamically via a database?
Both are on the planning list... I'm hoping to have a day free up where I can just sit down and belt this out.  In all a basic blogging system is only around 30 hours labor for "the basic" back end stuff. Most of the real dicking around time wasting is front-end.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 20 Nov 2020, 10:14:51 am
Can you also add a basic user registration system?

And if you are turning into a very basic CMS system - can the pages be generated dynamically via a database?
Both are on the planning list... I'm hoping to have a day free up where I can just sit down and belt this out.  In all a basic blogging system is only around 30 hours labor for "the basic" back end stuff. Most of the real dicking around time wasting is front-end.
Maybe I should just bin my code off and wait for yours...

Will it be free?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 20 Nov 2020, 12:08:39 pm
First impression...

(https://artdesignrocva.files.wordpress.com/2014/02/gizmodo-the-top-10-rube-goldberg-machines-featured-on-film-rube-goldberg.jpg)


But..... I am keeping an open mind and will play along to see where we end up. When you get to the right point, could you please provide a new download that implements all the working DB code.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: GrumpyYoungMan on 20 Nov 2020, 01:58:29 pm
Are you saying he has over complicated it?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 20 Nov 2020, 02:44:14 pm
Are you saying he has over complicated it?

To be fair to Jason, I will wait to see the full implementation before I comment on the code.

As far as a PDO database connection the following is 100% the only code needed to make a Mysql database connection. Anything beyond this should have a good reason for being there. And yes, there is more that "should" be there and valid reasons for it. I am sure we will end up getting into it, from the basic "should be there's" to Q&A for anything else.

You can test this with your own database. Just set the parameters to match your DB and then var_dump($pdo) to see the PDO Object.
Code: [Select]
$pdo = new PDO('mysql:dbname=test;host=127.0.0.1', 'root', 'password');
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: xmohamadx on 20 Nov 2020, 07:47:07 pm
Now, to help secure things there are going to be some standard practices in how SQL stuff should be named.

Is this a matter of style or it is to secure things? I know there was a time when most people did not have the possibility of encoding anything beyond upper case letters because ASCII was not yet invented. while SQL is more recent, lower case letters were not common practice in programming yet. but not a good reason today.


In template_extraPart:
Code: [Select]
function template_extrasPart($id, $extras) {

echo '

<div id="', $id, '">';

foreach ($extras as $id => $section) {
if (is_array($section)) {
template_sectionHeader($id, $section['title']);
if (array_key_exists('php', $section)) {
include_once('extras/' . $section['php'] . '.extra.content.php');
($section['php'] . '_SectionRun')();
$include = null;
}
if (array_key_exists('static', $section)) readFile(
'extras/' . $section['static'] . '.extra.static'
);
} else {
template_sectionHeader($id, $section);
readFile('extras/' . $id . '.extra.static');
}
template_sectionFooter($id);
}

echo '
<!-- #', $id, ' --></div>';

} // template_extrasPart


using $id in "foreach" make a conflict with the $id in argument, so the last echo "<!-- #', $id, ' --></div>" print wrong $id.
Also, "$include = null;" seems lost his way!
And if extra content be DB driven, there is no way here to send data from action_startup to extra template, so I added $data to "($section['php'] . '_SectionRun')($data);", and the data for extra can be merged to Settings::get('extra1') in template_footer. it seems better than to fetch data in ..._SectionRun() function.


In these three functions:
Code: [Select]
public function exec($name, $module = 'common', $tableName = false) {
return $this->dryStatement('exec', func_get_args());
} // Database::exec

public function prepare($name, $module = 'common', $tableName = false) {
return $this->dryStatement('prepare', func_get_args());
} // Database::prepare

public function query($name, $module = 'common', $tableName = false) {
return $this->dryStatement('query', func_get_args());
} // Database::query
the "func_get_args()" will not pass optional parameters and makes error.


Noticed some typos after testing:
in namedQuery:
Code: [Select]
if ($tableName) {
if ($this->safeName($name)) {
$query = str_replace('!TABLE!', $tableName, $query);
} else Bomb::paladin('invalidTableName', [ $tableName ]);
}
the $name need to change to $tableName in if ($this->safeName($name)).

in "httpError.php" and "paladinError.php", template_section need to change to template_sectionHeader. also template_sectionFooter(); need $id as argument.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 20 Nov 2020, 08:21:12 pm
@Jason Knight,
May I suggest during the update to possibly add three links in top menu, body and footer. Each link to describe how to add a new page with additional CSS and JavaScript.


Edit:
Please also include responsive images, etc
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 21 Nov 2020, 05:04:55 am
@xmohamadx,
> Noticed some typos after testing: in namedQuery:

I think a broad outline would have been adequate and once the script is throughly debugged then explain the details along with the debugged script.

Also think that using .ini files could have been far simplified by using php classes.

I look forward to a complete version and shudder to think about updates :(
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 21 Nov 2020, 12:15:44 pm
May I suggest during the update to possibly add three links in top menu, body and footer. Each link to describe how to add a new page with additional CSS and JavaScript.
Again the front-end / current template is placeholder ripped from something else, just so I could hit the ground running. Needs a rewrite or a lot of loving that comes a LOT later in the process.

I probably should have just had it spitting up vanilla markup instead of styled... but that doesn't "impress" the normies.

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 21 Nov 2020, 12:22:09 pm
Is this a matter of style or it is to secure things?
Little from column A, little from column B. Mostly it comes from some SQL backup systems mangling case due to filesystem differences; such as linux being case sensitive when windows is not.

In template_extraPart:

Mistakes I already caught when I actually started testing the code.

Though I've been finding myself making a lot of silly mistakes and flubs because I'd been away from PHP and SQL for six or seven months. Amazing how quickly skills and memory can fade from lack of use.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 21 Nov 2020, 12:32:57 pm
Anything beyond this should have a good reason for being there.

Which the reasons it has all the extra stuff:

1) block willy-nilly queries

2) allow named queries to allow for multi-engine coding. There's more in the world than mysql

3) embed better error handling that automatically logs and bombs hiding information from the client-side.

4) pre-build some checks we'd use frequently. ->tableExists for example can be used to detect if the database has already been set up, locking you out of setup or locking general users out of the system before setup has been run.

5) isolate and clean things prepare/execute doesn't let you placeholder, like table names

6) automatically add table prefixes.

Named queries and helper methods have a lot of benefits.

Code: [Select]
if (!$db->tableExists('users')) Bomb::paladin('dbTablesMissing');

For example. Should be relatively clear what that line does, even if you don't know all the methods.

Just as:

Code: [Select]
private static function touch() {
if (
array_key_exists('id', self::$data) &&
(self::$data['id'] !== -1)
) self::$db->prepExec([ self::$data['id'] ], 'touch', 'user');
} // User::touch

Is nicer than:

Code: [Select]
private static function touch() {
if (
array_key_exists('id', self::$data) &&
(self::$data['id'] !== -1)
) {
$stmt = $db->prepare('
UPDATE ', DB_TABLE_PREFIX, 'users
SET last_access = CURRENT_TIMESTAMP
WHERE id = ?
');
$stmt->exec([ self::$data['id'] ]);
}
} // User::touch

Especially if you want the possibility of multi-engine support in the mix. Again, there's a world outside mysql.

Note, since the primary call is self::touch(); that should be done in private.

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 21 Nov 2020, 07:56:21 pm
@Jason Knight,
This may be of interest...

In my last project I have a PDO Class with methods that use strict_types and especially for the return $result. Each method  accepts at least a string query and returns either bool, numeric, string, array or object.

When testing for a valid user I would try something similar to:

$ok = $this -> pdo -> _tryBool( ‘UPDATE ‘users‘ WHERE ‘id‘=‘ .$id );



Edit:
MySQL has a built in feature that automatically sets ‘last_access‘ with a TIMESTAMP.
MySQL has a built in feature that sets ‘last_access‘ with a TIMESTAMP automatically.

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 21 Nov 2020, 10:11:26 pm
MySQL has a built in feature that automatically sets ‘last_access‘ with a TIMESTAMP.
Unfortunately it does so even on a casual access, making it useless for our purposes. I don't want failed logins or accesses that merely read some data about a user to trigger last access.

It's also an engine specific feature, which I want to avoid.

As to the asshat pedantic strict_types rubbish, NOT INTERESTED. Besides, fetchColumn isn't exactly rocket science.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 22 Nov 2020, 02:40:32 am
@Jason Knight


My point is that when I know either a true of false will be returned then why unnecessarily increase complexity? Just test for a valid user?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 22 Nov 2020, 01:38:49 pm
What are the exact steps to add a new page?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 22 Nov 2020, 02:35:47 pm
What are the exact steps to add a new page?
Assuming you want a static content page, you go to /actions/static/ and make a new directory for the new page that's the identifier you want the page to be. For example let's make a "/dumb_page"

So make the folder:

/actions/static/dumb_page

make these two files:

/actions/static/pages/dumb_page/dumb_page.ini.php
/actions/static/pages/dumb_page/dumb_page.static

The first one contains information unique to the page such as the keywords or description, the latter contains the static markup to be plugged into <main>.

look at the default.ini.php:

Code: [Select]
; <?php die(); // prevent direct calls just in case

currentPage "Home"

[meta]
keywords[name] = "keywords"
keywords[content] = "Default, Template, Poor, Man, Content, Management"

description[name] = "description"
description[content] = "Default Demo for Poor Man's Content Management"

currentPage is the text content of the menu item you want the "current" class to highlight.  [meta] holds any meta you want set, the index of each you can make up so long as it's unique, [name] is the name attribute, [content] is the content attribute. I didn't go with name="content" because some ****wits at various search engines up and decided to make up their own blasted "property" attribute instead of using "name" so they could use otherwise invalid values. (aka "wah wah, I want a colon in name because I can't live with a hyphen" -- see the asshattery that is opengraph)

If you look at /test/ you can see that it uses a .content.php instead of a .static, where you have a function (action_content) example for when/if you need to plug values -- HTTP_ROOT for example -- into the markup with PHP, building semi-static sites.

The big difference being that .static is loaded via readfile, and .content.php is loaded via safeInclude.

But really, create that directory, create those two files, boom, new page.

If you want to make a dynamic page, you make a /action/actionName directory, create a actionName.startup.php that returns the $data of the operation. This $data array should include:

'contentFilePath' => 'actions/actionName/actionName[.result]'

That will be used to load the corresponding .static or .content.php files.

Look at /actions/contact for an example. Note that "actions" can use both .content.php and .static (which load in that order), whilst with static it's either-or.

Basically, make a directory, make two files, done. Note that these files correspond to how one would/should access / store things in the database if one moves from file driven to content driven.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 22 Nov 2020, 04:30:20 pm
Quote
Basically, make a directory, make two files, done.

Yeah, apparently not.

Code: [Select]
404 - Not Found

Your request "/static/dumb_page" could not be served at this time.

I moved the dumb_folder and files to /actions/pages/dumb_page/ where the test folder is and a page loads at URL http://squire3.test/static/dumb_page with sample 1 and sample 2 data from the extras folder that I nowhere told it to load. Additionally, the text in sample 2 is mangled. WTF?

So far I give this "architecture" a big fail. But....I will keep on and see it through to the end, that is if I can even do the simple task of adding a static page.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: xmohamadx on 22 Nov 2020, 05:57:26 pm
@benanamen, sorry for interfering, but as I'm already using this architecture for my back-end, with some dynamic and static pages, I can help to fix those problems.

I moved the dumb_folder and files to /actions/pages/dumb_page/
Actually you should put them inside /actions/static/pages/dumb_page/, you forgot the "static".

also note that you need to have a "dumb_page.ini.php" or "dumb_page.startup.php", otherwise it returns a 404 error because no datasource has been added.

with sample 1 and sample 2 data from the extras folder that I nowhere told it to load. Additionally, the text in sample 2 is mangled. WTF?
well, then this is odd! because in httpError page this line should exist:
Code: [Select]
Settings::set(true, 'noExtras');and this line overrides the default behavior in "user.ini" which says there is two extra.

anyway, I found it simple and organized, just need to trace from the index to find out how it works.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 22 Nov 2020, 11:00:11 pm
I added a "Info" link in the page header and managed to create a new "info" web-page along with a direcory screendump:

https://thisisatesttoseeifitworks.tk/deathshadow/static/info
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 23 Nov 2020, 12:06:13 am
Actually you should put them inside /actions/static/pages/dumb_page/, you forgot the "static".
Actually that's a my bad, I forgot the /pages/ in the instructions. I'm so used to just doing it that I documented it poorly. That's entirely on me.

I edited the post to reflect that. What I get for posting half-asleep with insomnia.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 23 Nov 2020, 12:49:36 am
Quote
Actually you should put them inside /actions/static/pages/dumb_page/, you forgot the "static".

That is exactly where I put it, I didn't "forget" anything. I made a typo in my post.

Quote
also note that you need to have a "dumb_page.ini.php" or "dumb_page.startup.php", otherwise it returns a 404 error because no datasource has been added.

I already have dumb_page.ini.php in /actions/static/pages/dumb_page/ as well as /actions/static/pages/dumb_page/dumb_page.static


Quote
anyway, I found it simple and organized,

If you think this is simple, just wait till I show you something after we get through this code. This code is far from simple and way more complicated than it needs to be.

I will see about "debugging" this code tomorrow. I was trying to go at it without having to step through the code and the way Jason described it, it was supposed to be simple, just do this and that and it works. Not the case. This code already goes against "The Principle of Least Astonishment".


Thank you for your feedback.


EDIT:


Thanks to Johns page I was able to get a static page to work. I had to rename dumb_page.static to dumb_page.content.php and add noExtras=TRUE to dumb_page.ini.php

Much to my astonishment (Thus violating The Principle of Least Astonishment") If you remove noExtras=TRUE it starts spitting out all the sample text stuff. Seriously, WTF is that all about?

@xmohamadx, none of the info you provided was needed and only confused the matter but I appreciate you trying to help.  :)

* Something to come back to later: dumb_page.content does not need function action_content() to output anything. You can just echo something or type plain text outside php tags. I am not sure what the intention is supposed to be.

I digress, lets move on to the DB stuff when Jason has time. There is already a lot of stuff to talk about thus far, but let's wait to see the final product.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: xmohamadx on 23 Nov 2020, 08:04:37 am
@xmohamadx, none of the info you provided was needed and only confused the matter but I appreciate you trying to help.  :)
Sorry for the confusion.

I had to rename dumb_page.static to dumb_page.content.php
I did it with "*.static" and no problem happened.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 23 Nov 2020, 07:55:52 pm
Much to my astonishment (Thus violating The Principle of Least Astonishment") If you remove noExtras=TRUE it starts spitting out all the sample text stuff. Seriously, WTF is that all about?
Sidebars / extras for three column layouts? You'll be able to declare them on a /action/ basis in the final, they're hardcoded into the ini file for now just to test that you can load extras.

See /extras/ for their content.

It's a in-built system for multiple pages to share sidebars, such as advertisements, secondary navigation and so forth. The underlying template is three column-ready. On the next copy those will be determined off the database settings for posts and/or the startup setting them instead of the .ini

You are aware some websites have fixed sidebars for things, right?
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 23 Nov 2020, 08:17:35 pm
Quote
You are aware some websites have fixed sidebars for things, right?

The "surprise" was how it is implemented, not that sidebars exist.

When do you think you might have a database implementation?

Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 24 Nov 2020, 04:30:56 am
* Something to come back to later: dumb_page.content does not need function action_content() to output anything. You can just echo something or type plain text outside php tags. I am not sure what the intention is supposed to be.
action_content is there for passing $data from the starter, so as to isolate the scope of the data. It would be used for the process > output process, not for static pages.

It's also not a great idea for static to just be blindly vomited up in a .content.php since that's a possible XSS vulnerability based on the data-source. Safe-include helps with that to a degree, but there's a REASON .static is loaded via readfile, and .content.php should contain a function and is loaded via safeInclude.

It's all part of the internal security policy to prevent scope bleed.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 24 Nov 2020, 08:20:41 am
@Jason Knight,

If you had used strict_types and set the function parameter to (array $data=[] ) it would have eliminated any confusion :)
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 24 Nov 2020, 10:25:22 am
.static is loaded via readfile, and .content.php should contain a function
It's all part of the internal security policy to prevent scope bleed.

That was going to be another one of my questions, why readfile in one place and function in another. Thanks for the explanation.

I will refrain from forming any opinions until I see the "final" product. Still keeping an open mind and hoping to learn some new things. Really interested to see the database implementation.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 25 Nov 2020, 12:27:02 am
I have created a the following GitHub Repository:

https://github.com/John-Betong/jb-squire3 (https://github.com/John-Betong/jb-squire3)

Modifications detailed in the README.md

I think there must be more source files required in the "003-sys" folder? Seems too good to be true? If not then I am really growing to like this project because:

1. it is clean and simple now that it is split into three separate folders
2. maintenance should only involve the "003-sys" folder

Looking forward to the database additions.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 27 Nov 2020, 09:17:28 am
Ok, small update.

First I just want to say you folks input and experiences is helping me refine this. The "lack of clarity" of what is and is not squire has resulted in me moving most of what "is" squire into it's own squire.lib.php that replaces common.lib.php

I put the source for that here:
https://cutcodedown.com/for_others/squire3/squire4.beta.lib.phpSource

I actually have the database and installer (which creates the admin user) complete, I'm starting in on the user section after another DDCR and testing pass.

The new index.php looks something like this:

Code: [Select]
<?php

/*
index.php 27NOV20:0908
Paladin X.4 (Squire 4.0) 
"one index to rule them all"
Jason M. Knight, November 2020
*/

include('libs/main.lib.php');

main(
'mysql:dbname=paladinx.3;host=localhost'// dsn
'paladinTesting'// username
''// password
[
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
], 
// options
'paladin' // table_prefix
);

I reduced it to this to simplify "normals" editing the credentials.

whilst lib/main.lib.php reads: (for now)

Code: [Select]
<?php
/*
main.lib.php
Paladin X.4 (squire 4.0)
Jason M. Knight, November 2020
*/

include('libs/squire.lib.php');
include(
'libs/user.lib.php');

define(
'TEMPLATE_PATH',
'templates/' . (Settings::get('template') ?: 'default') . '/'
);

Load::template('common');

function 
main($dsn$username$password$options$tablePrefix) {

Bomb::ifStarted('main');

define('SQL_ENGINE'strstr($dsn':'true));
safeInclude('database/' SQL_ENGINE '/' SQL_ENGINE '.database.php');
$db = new Database($dsn$username$password$options$tablePrefix);

if (!$db->tableExists('users')) {
define('DB_TABLES_EXIST'false);
if (Request::value() !== 'setup'Bomb::paladin('dbTablesMissing');
} else define('DB_TABLES_EXIST'true);

if (DB_TABLES_EXIST) {
if (!empty($_REQUEST['logout'])) $_SESSION['user'] = null;
User::init($db);
if (User::get('id') < 0Modals::set(
'login''@title_loginModal'htmlspecialchars($_SERVER['REQUEST_URI']), 'POST'
); else Modals::set('userMenu'User::get('name'));
}

action($db);

// main

The template define is probably going to be moved into settings and/or set ny template_header so the user accounts can override it. That way users can change templates once more than one is implemented.

Template handling also needs some expansion so that it cascades back to default so you don't have to clone every file, you can just "overload" the ones you want to change.

Code: [Select]
<?php
/*
mysql.database.php 27NOV20:0914
Paladin X.4 (Squire 4) 
Jason M. Knight, November 2020
*/

final class Database extends PDO {

private
$authorizations = [],
$queries = [];

// START PUBLIC OVERLOADS

public function __construct(
$dsn,
$username,
$password,
$options = [],
$tablePrefix false
) {

if (defined('DB_CONSTRUCTED')) Bomb::lang(
'HACKING ATTEMPT DETECTED',
'Attempt to create "Database" more than once'
);
define('DB_CONSTRUCTED'1);

$options[PDO::ATTR_STATEMENT_CLASS] = [ 'DatabaseStatement', [ $this ] ];

try {
parent::__construct($dsn$username$password$options);
} catch (PDOException $e) {
Bomb::lang('Database Connection Error'$e );
}

define('DB_TABLE_PREFIX'$tablePrefix $tablePrefix '_' '');
define('DB_QUERY_DIR''database/' SQL_ENGINE '/queries/');

// Database::__construct

public function exec($name$module 'common'$tableName false) {
return $this->dryStatement('exec'$name$module$tableName);
// Database::exec

public function prepare($name$module 'common'$tableName "wtf") {
return $this->dryStatement('prepare'$name$module$tableName);
// Database::prepare

public function query($name$module 'common'$tableName false) {
return $this->dryStatement('query'$name$module$tableName);
// Database::query

// END PUBLIC OVERLOADS

// START PUBLIC EXTENSIONS

public function prepExec($data = [], $name$module 'common'$tableName false) {
$stmt $this->prepare($name$module$tableName);
$stmt->execute($data);
return $stmt;
// Database::prepExec

public function rowCount($tableName) {
$stmt $this->query('rowCount''common'$tableName);
return $result->fetchColumn();
// Database::rowCount

public function safeName($name) {
return $name preg_replace('/[^a-z0-9_]/'''$name);
// Database::safeName

public function tableExists($name) {
$stmt $this->query('tableExists''common'$name);
return $stmt->fetch();
// Database::tableExists

// END PUBLIC EXTENSIONS

// START PRIVATE EXTENSIONS

private function auth($name$module) {

if ($module === 'common') return true;

if (!array_key_exists($module$this->authorizations)) {
if (file_exists(
$fn DB_QUERY_DIR $module '/' $module '.auth.ini.php'
)) $this->authorizations[$module] = parse_ini_file($fn);
else return true;
}

return (
($this->authorizations[$module][$name] ?? 0) ||
($this->authorizations[$module]['all'] ?? 0)
) !== 0;

// Database::auth

private function dryStatement($method$name$module$tableName) {
try {
$stmt parent::$method($this->namedQuery($name$module$tableName));
} catch (PDOException $e) {
$errorMessage $e->getMessage();
echo $errorMessage'<br>wtf<br>';
}
if (
$method !== 'exec' &&
($stmt->errorCode() > 0)
$errorMessage $stmt->errorInfo()[2];
if (empty($errorMessage)) return $stmt;
Bomb::lang(
'db' ucFirst($method) . 'Error',
$name$module$errorMessage ]
);
// Database::dryStatement

private function namedQuery($name$module "common"$tableName false) {

if (!$this->auth($name$module)) Bomb::lang(
'unauthorizedQuery', [ $name$module ]
);

if (!array_key_exists($module$this->queries)) {
$this->queries[$module] = file_exists(
$fn DB_QUERY_DIR $module '/' $module '.queries.ini.php'
) ?  parse_ini_file($fn) : [];
}

if (!array_key_exists($name$this->queries[$module])) {
if (file_exists(
$fn DB_QUERY_DIR $module '/' $module '.' $name '.sql'
)) $this->queries[$module][$name] = file_get_contents($fn);
else Bomb::lang('queryNotFound', [ $name$module ]);
}

$query str_replace(
'!PREFIX!',
DB_TABLE_PREFIX,
$this->queries[$module][$name]
);

if ($tableName) {
if ($this->safeName($name)) {
$query str_replace('!TABLE!'$tableName$query);
} else Bomb::lang('invalidTableName', [ $tableName ]);
}

return $query;

// Database::namedQuery

// END PRIVATE EXTENSIONS

// Database

class DatabaseStatement extends PDOStatement {

private
$pdo,
$locked false;

protected final function __construct($pdo) {
$this->pdo $pdo;
// DatabaseStatement:__construct

public final function execute($input_parameters Null) {
if ($this->lockedBomb::lang('executeLockedStmt');
return parent::execute($input_parameters);
// DatabaseStatement::execute

public final function lock() {
$this->locked true;
// DatabaseStatement::lock

// DatabaseStatement

Side note, once I get this thing further along, anyone want to take a stab at writing a MSSQL version, or perhaps other ports? Should be as "easy" as making a new /sql/SQL_ENGINE directory and double-checking the queries.

That's one of my big "features" is how if PDO is going to be portable, let's make it PORTABLE!
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 29 Nov 2020, 09:50:09 pm
Noticed you guys seem to like having a full directory structure listing in the various posts about this, so I've added that to my milestone script, generating both HTML and TXT versions.

Sample output here:
https://cutcodedown.com/paladinX/milestone_30_Nov_2020_02_44/

Work on users has FINALLY started, hopefully I won't fall asleep before I'm done. So tired lately.

Note, rather than relying fully version codes, the primary tracking for this system is going to be milestone dates.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: John_Betong on 29 Nov 2020, 11:41:16 pm
@Jason Knight,
> Sample output here:
https://cutcodedown.com/paladinX/milestone_30_Nov_2020_02_44/ (https://cutcodedown.com/paladinX/milestone_30_Nov_2020_02_44/)

Not another link and once again with no back link :(

How do you keep track?

I'm getting more confused everyday! 

The project started November 9th and a complete version was envisaged in a couple of days. Since then there has been very little updates and only discussions?

As mentioned in my "Proposal" thread... is it possible to consolidate the vast amount of waffle and to simplify the task in hand... pretty please :)



Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 30 Nov 2020, 04:51:53 am
Not another link and once again with no back link :(
Back link to what? That's just a preview of what the milestone generator outputs alongside the backup.

How do you keep track?
Of what?

I'm getting more confused everyday! 
You and me both brother.

The project started November 9th and a complete version was envisaged in a couple of days.
That was NOT a "complete version", I had thought it was enough to give @benanamen something for his "router or not" thread, but it clearly was not. I only broke it out into a continuing project because so many of you seemed to be interested in picking it up and running with it... before it was really ready for anyone but me to even work with.

Though I must have done SOMETHING right given how many of you are trying to use it months before it's ready... or at least months given the 20 or so minutes a day I'm able to work on it.  I'd LOVE to just have one day where I could sit down and put 8-10 straight hours into it, but that's just not happening.

As mentioned in my "Proposal" thread... is it possible to consolidate the vast amount of waffle and to simplify the task in hand... pretty please :)
Thing is all these threads are NOT even about the real system which I've not even come close to finishing. What you've seen so far was a quick belt together of half-assed code to try and answer a question. The interest on you folks part is what has be upping the ante and building it "for real".

I'm not sure what part of this people aren't understanding. I mean, if we're going to have these attitudes I could just drop it and devote the time to writing more medium articles, which are now paying monthly more than adsense has paid me in a decade.

But really between writing articles on medium which pays, paying clients, a holiday that takes 2 days of prep and 3 days of cleanup... right now I look at code I get dizzy... and I'm making rookie mistakes. (good gravy, I can't seem to type non-alphanumeric characters anymore! Parkinson's a bitch. Seriously, @ through & I have to stop and actually look at the keyboard now.)

Let me upload a proper milestone with the admin system gutted out of it, that way you can see database, login, and an installer.

Though to simplify the process, maybe I should make a forum category for squire/paladin where a unique topic can be created for each milestone (subversion). That way discussion unique to each release can be isolated. (with old versions locked).

Could also make topics

BUT, once I have what I'd consider a beta release, I will likely document all the files and sub-calls the same way I did elementals.js. Might not be the best JS library, but I'm proud of its documentation. Just like my x86 asssembler reference.  I'm planning to document this the same way when/if I have the time. That directory output from the milestone generator will likely aid in that, particularly since I'm likely going to have it also create a cross-reference of the objects and their methods. Though I'm a bit uncertain how to go about that with PHP. Classic tool I've not seen a version for modern languages in like two decades! Might have to brute force it.

I wonder if I could create general descriptions as .txt and have the directory tree link / ajax them into modals. Well, I could create that, when/if I'm able to sit down at the workstation and code properly.

Which is also a bit of a wonk since I need to take that machine apart for an upgrade... whilst I sit here flat on my back in bed and unlikely to get up for the next 48 hours to do anything more than take a whiz... since I'm SUPPOSED to have the first visit from a new caregiver tomorrow; which I'm SUPPOSED to have but have gone without since the stupid human malware problem started.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: benanamen on 30 Nov 2020, 01:41:11 pm
I really like the output of the html directory tree here https://cutcodedown.com/paladinX/milestone_30_Nov_2020_02_44/

Do you have some generator to do that? If so, would you willing to provide the code? Thanks
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: mmerlinn on 30 Nov 2020, 11:36:05 pm
I really like the output of the html directory tree here https://cutcodedown.com/paladinX/milestone_30_Nov_2020_02_44/

Do you have some generator to do that? If so, would you willing to provide the code? Thanks

I like it, too.  Looks like it would be useful everywhere that directories are used. Might even code something in FoxPro to keep track of all of its directories. Only problem I have is knowing what all of the 01F-4C1 and 01F-5CF notes mean.
Title: Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
Post by: Jason Knight on 1 Dec 2020, 12:02:51 am
Do you have some generator to do that?

It's part and parcel of my milestone generator.

I have:

/paladinX -- project root
/paladinX/milestone.php
/paladinX/paladin -- working directory

when I run milestone.php, it:

1) copies /paladin to miliestone_datestamp/paladin, updating the comment timestamps in all code files

2) makes a copy to /sources where all .php files are renamed phpsource to show code instead of executing

3) makes a "milestone_datestamp/milestone_datestamp.zip" of the contents of /milestone_datestamp/paladin

4) makes those two directory listings

5) optionally FTP uploads it to where you guys can access it.

Pretty routine stuff I have for a lot of projects. Elementals.js is self updating in a similar fashion.

Oh and sorry this milestone was broken, self-pressured myself into uploading before it was ready. Hopefully this next one -- which should include a rough draft admin panel with user creation -- will be less of a mess.

REALLY hoping that I am able to actually code this tonight. I seem to be having a lot of problems typing right now; my fingers are all over the place on anything that's not alphanumeric.

That I'm not on the model M at the workstation likely isn't helping.