CUTCODEDOWN
Minimalist Semantic Markup

Welcome Guest
Please Login or Register

If you have registered but not recieved your activation e-mail in a reasonable amount of time, or have issues with using the registration form, please use our Contact Form for assistance. Include both your username and the e-mail you tried to register with.

Author Topic: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.  (Read 10049 times)

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #45 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...
« Last Edit: 18 Nov 2020, 12:57:18 am by Jason Knight »
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

John_Betong

  • Full Member
  • ***
  • Posts: 218
  • Karma: +24/-1
    • The Fastest Joke Site On The Web
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #46 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.
Retired in the City of Angels where the weather suits my clothes

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #47 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.
« Last Edit: 18 Nov 2020, 10:33:38 am by Jason Knight »
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

benanamen

  • Full Member
  • ***
  • Posts: 188
  • Karma: +18/-0
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #48 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>');
}
« Last Edit: 18 Nov 2020, 12:02:13 pm by benanamen »
To save time, let's just assume I am never wrong.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #49 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.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

benanamen

  • Full Member
  • ***
  • Posts: 188
  • Karma: +18/-0
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #50 on: 18 Nov 2020, 06:38:04 pm »
Looking forward to seeing your database implementation when you can get to it.
To save time, let's just assume I am never wrong.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #51 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.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #52 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.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #53 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
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

GrumpyYoungMan

  • Hero Member
  • *****
  • Posts: 787
  • Karma: +8/-0
    • Grumpy Young Man
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #54 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?
Trying to learn a new trick to prove old dogs can learn new ones...

Total Novice have-a go Amateur Programmer - not sure that is the right thing to say... but trying to learn...

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1049
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #55 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.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

GrumpyYoungMan

  • Hero Member
  • *****
  • Posts: 787
  • Karma: +8/-0
    • Grumpy Young Man
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #56 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?
Trying to learn a new trick to prove old dogs can learn new ones...

Total Novice have-a go Amateur Programmer - not sure that is the right thing to say... but trying to learn...

benanamen

  • Full Member
  • ***
  • Posts: 188
  • Karma: +18/-0
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #57 on: 20 Nov 2020, 12:08:39 pm »
First impression...




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.
To save time, let's just assume I am never wrong.

GrumpyYoungMan

  • Hero Member
  • *****
  • Posts: 787
  • Karma: +8/-0
    • Grumpy Young Man
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #58 on: 20 Nov 2020, 01:58:29 pm »
Are you saying he has over complicated it?
Trying to learn a new trick to prove old dogs can learn new ones...

Total Novice have-a go Amateur Programmer - not sure that is the right thing to say... but trying to learn...

benanamen

  • Full Member
  • ***
  • Posts: 188
  • Karma: +18/-0
Re: Squire 3 / Paladin X.3 -- Rebuilding from the ground up.
« Reply #59 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');
To save time, let's just assume I am never wrong.

 

SMF spam blocked by CleanTalk

Advertisement