Jump to content

Strider64

Members
  • Posts

    332
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by Strider64

  1. I personally like leaving the HTML on the page itself as I like doing HTML/CSS mock-ups then just adding to the PHP to the HTML. For example - <main> <?php foreach ($cms as $record) { ?> <article class="cms"> <img class="article_image" src="<?php echo htmlspecialchars($record['image_path']); ?>" <?= getimagesize($record['image_path'])[3] ?> alt="article image"> <h2><?= $record['heading'] ?></h2> <span class="author_style">Created by <?= $record['author'] ?> on <time datetime="<?= htmlspecialchars(CMS::styleTime($record['date_added'])) ?>"><?= htmlspecialchars(CMS::styleDate($record['date_added'])) ?></time></span> <p><?= nl2br($record['content']) ?></p> <?php echo (isset($_SESSION['id'])) ? '<a class="editButton" href="edit.php?id= ' . urldecode($record['id']) . '">Record ' . urldecode($record['id']) . '</a>' : null; ?> </article> <?php } $url = 'index.php'; echo $pagination->new_page_links($url); ?> </main> I have a Database Object class An example (not the whole code) - namespace Techshangri; use mysql_xdevapi\Exception; use PDO; use PDOException; class DatabaseObject // The Parent Class: { static protected string $table = ""; // Overridden by the calling class: static protected array $db_columns = []; // Overridden by the calling class: static protected array $objects = []; static protected array $params = []; static protected $searchItem; static protected $searchValue; /* * Pagination static function/method to limit * the number of records per page. This is * useful for tables that contain a lot of * records (data). */ public static function page($perPage, $offset, $loc = 'index'): array { $sql = 'SELECT * FROM ' . static::$table . ' WHERE page=:page ORDER BY date_added DESC LIMIT :perPage OFFSET :blogOffset'; $stmt = Database::pdo()->prepare($sql); // Prepare the query: $stmt->execute(['perPage' => $perPage, 'blogOffset' => $offset, 'page' => $loc]); // Execute the query with the supplied data: return $stmt->fetchAll(PDO::FETCH_ASSOC); } // more code... and I have a Children's class that is more specific: Children's Class (CMS.php) - Example - class CMS extends DatabaseObject { protected static string $table = "cms"; // Table Name: static protected array $db_columns = ['id', 'user_id', 'thumb_path', 'image_path', 'Model', 'ExposureTime', 'Aperture', 'ISO', 'FocalLength', 'author', 'heading', 'content', 'data_updated', 'date_added']; public $id; public $user_id; public $page; public $thumb_path; public $image_path; public $Model; public $ExposureTime; public $Aperture; public $ISO; public $FocalLength; public $author; public $heading; public $content; public $date_updated; public $date_added; /* * Construct the data for the CMS */ public function __construct($args = []) { // $this->user_id = $args['user_id'] ?? null; // $this->author = $args['author'] ?? null; // $this->heading = $args['heading'] ?? null; // $this->content = $args['content'] ?? null; // $this->date_updated = $args['date_updated'] ?? null; // $this->date_added = $args['date_added'] ?? null; // Caution: allows private/protected properties to be set foreach ($args as $k => $v) { if (property_exists($this, $k)) { $v = static::filterwords($v); $this->$k = $v; static::$params[$k] = $v; static::$objects[] = $v; } } } // End of construct method: public static function styleTime($prettyDate): string { try { $dateStylized = new DateTime($prettyDate, new DateTimeZone("America/Detroit")); } catch (Exception $e) { } return $dateStylized->format("Y-m-d H:i:s"); } // more code... I use Active Record Design Pattern as for what I do doesn't get too complex and besides I'm starting to like this pattern. However, if I was doing a really large website I would go more the route of Model-View-Controller pattern. Well, at least I think I would? Anyways, I getting off topic and my point is that after struggling with OOP for awhile, I found out by doing tutorials and looking at examples is to keep your methods and even you classes as short as possible, plus try to have meaning to them that is helpful to you as the coder. The real benefit now is that I can transfer these classes over to other projects (websites) with no problem and that is when I find out if I have written a class that could had been written better. As I sometimes find myself getting a little carried away with a class or putting a method (or even the variables) in the wrong class. I always shoot myself when I do that when come to that realization. 🤣 Everyone codes differently, but that is my logic.
  2. Another thing is PHP OOP is great with inheritance where a lot of that code to put it nicely could be streamline and some of the methods wouldn't even have to be used. Something to look into?
  3. Warning Do not use extract() on untrusted data, like user input (e.g. $_GET, $_FILES). This coming from https://www.php.net/manual/en/function.extract.php
  4. A good thing to have is a good IDE that will point out the common syntax errors and find good resources/tutorials online to help with the logic flow. As for Database Tables I like using PDO and I still go to the following online resource when I get stump or have a brain fart. https://phpdelusions.net/pdo 🤣 I go here and other forums to see if someone before me has had the same problem and if not I will attempt to ask a question while showing my work. I learn over the years not to show too little or way too much code. I find commenting code help not only me but the people helping me trying to solve my problem(s).
  5. From what I am see is that you are doing too much inside methods and even the classes. Keep methods simple as possible such as the following example: public static function page($perPage, $offset, $loc = 'index'): array { $sql = 'SELECT * FROM ' . static::$table . ' WHERE page=:page ORDER BY date_updated DESC LIMIT :perPage OFFSET :blogOffset'; $stmt = Database::pdo()->prepare($sql); // Prepare the query: $stmt->execute(['perPage' => $perPage, 'blogOffset' => $offset, 'page' => $loc]); // Execute the query with the supplied data: return $stmt->fetchAll(PDO::FETCH_ASSOC); } Classes can be inherited from a parent class or even another child class (However, I wouldn't go too deep) There are other ways of doing inheritance as well and some people frown on doing the way I do, but from what I do is small compared to larger development places. class CMS extends DatabaseObject { protected static string $table = "cms"; // Table Name: static protected array $db_columns = ['id', 'user_id', 'thumb_path', 'image_path', 'Model', 'ExposureTime', 'Aperture', 'ISO', 'FocalLength', 'author', 'heading', 'content', 'data_updated', 'date_added']; public $id; public $user_id; public $page; public $thumb_path; public $image_path; public $Model; public $ExposureTime; public $Aperture; public $ISO; public $FocalLength; public $author; public $heading; public $content; public $date_updated; public $date_added; /* * Create a short description of content and place a link button that I call 'more' at the end of the * shorten content. */ #[Pure] public static function intro($content = "", $count = 100): string { return substr($content, 0, $count) . "..."; } I do that with my PDO Database Connection that I call the Grandparent (called Database and I utilize it by doing Database::pdo() ). I go by the the K.I.S.S. (Keep It Simple Stupid) model as I find out that I write less code and can be used over and over again. I find myself (as I sure others do to) when I try to get fancy and write a bunch of code it leads to write more code with the class end up being longer than they should. Granted having a long class is sometimes unavoidable, but even them after you gain more knowledge of PHP can be streamline. I learn something new everyday in PHP coding (and other languages) and sometimes I slap myself why didn't I think of that. 🤣
  6. Actually using Fetch in Vanilla JavaScript is pretty easy to do: (Here's an example) /* Success function utilizing FETCH */ const sendUISuccess = function (result) { //console.log('Result', result); if (result) { d.querySelector('#recaptcha').style.display = "none"; submit.style.display = "none"; notice.style.display = "grid"; notice.textContent = "Email Successfully Sent!"; notice.style.color = "green"; message.style.display = "grid"; //messageSuccess.style.display = "block"; d.querySelectorAll('form > *').forEach(function (a) { a.disabled = true; }); } }; /* If Database Table fails to update data in mysql table */ const sendUIError = function (error) { console.log("Database Table did not load", error); }; const handleSaveErrors = function (response) { if (!response.ok) { throw (response.status + ' : ' + response.statusText); } return response.json(); }; const saveRequest = (sendUrl, succeed, fail) => { fetch(sendUrl, { method: 'POST', // or 'PUT' body: JSON.stringify(sendEmail) }) .then((response) => handleSaveErrors(response)) .then((data) => succeed(data)) .catch((error) => fail(error)); }; though jQuery has jQuery.get() I believe which is the same thing as Fetch in Vanilla JavasScript which might be worth looking into? In my opinion it easier and coding is more logical. I like that you don't have to worry about parsing the data and handling errors is easy to do. In your case you could make a fallback option or tell the other player that the other person is no longer online.
  7. Why don't you just extend the child class? Does it work in the parent class? If it doesn't then there is something wrong with self::$conn You might be initializing the database connection before it is called?
  8. I would suggest using namespaces and an autoloader using composer. A good link in my opinion is this one - https://phpenthusiast.com/blog/how-to-autoload-with-composer and it really help me understand on how to do it. Then you simply can do this : <?php require_once 'assets/config/config.php'; // You still need your trusty configuration file require_once "vendor/autoload.php"; // Autoloader using composer use PhotoTech\CMS; use PhotoTech\Pagination; Here's my Database Class: <?php namespace PhotoTech; use PDO; class Database { private PDO $_connection; // Store the single instance. private static ?Database $_instance = null; // Don't initialize before it is called: // Get an instance of the Database. // @return Database: protected static function getInstance(): Database { if (!self::$_instance) { self::$_instance = new self(); } return self::$_instance; } public static function pdo(): PDO { $db = static::getInstance(); return $db->getConnection(); } // Constructor - Build the PDO Connection: public function __construct() { $db_options = array( /* important! use actual prepared statements (default: emulate prepared statements) */ PDO::ATTR_EMULATE_PREPARES => false /* throw exceptions on errors (default: stay silent) */ , PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION /* fetch associative arrays (default: mixed arrays) */ , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); $this->_connection = new PDO('mysql:host=' . DATABASE_HOST . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD, $db_options); } // Empty clone magic method to prevent duplication: private function __clone() { } // Get the PDO connection: protected function getConnection(): PDO { return $this->_connection; } } I have been using it for sometime without any problems and to use it I simply do the following class DatabaseObject // Extended by the children class: { static protected string $table = ""; // Overridden by the calling class: static protected array $db_columns = []; // Overridden by the calling class: static protected array $objects = []; static protected array $params = []; static protected $searchItem; static protected $searchValue; /* * There is NO read() method this fetch_all method * basically does the same thing. The query ($sql) * is done in the class the calls this method. */ public static function fetch_by_column_name($sql) { $stmt = Database::pdo()->prepare($sql); // Database::pdo() is the PDO Connection $stmt->execute([ static::$searchItem => static::$searchValue ]); return $stmt->fetch(PDO::FETCH_ASSOC); } // More coding... I should mention I am using PHP 8, so there might be some adjustment that might be needed? I also make comments that are sometime mental notes to me in order to know what I was doing. 😉
  9. Where static really shines is when you using an Active Record Design Pattern (I would assume other patterns are the same way, but this is the only pattern that I have used so far), for example: The Data Object Class class DatabaseObject // Extended by the children class: { static protected string $table = ""; // Overridden by the calling class: static protected array $db_columns = []; // Overridden by the calling class: static protected array $objects = []; static protected array $params = []; static protected $searchItem; static protected $searchValue; // More code.... A Children Class example class CMS extends DatabaseObject { protected static string $table = "cms"; // Table Name: static protected array $db_columns = ['id', 'user_id', 'thumb_path', 'image_path', 'Model', 'ExposureTime', 'Aperture', 'ISO', 'FocalLength', 'author', 'heading', 'content', 'data_updated', 'date_added']; // More Code....
  10. This deals with auto loading classes in php, but it should help you -> https://phpenthusiast.com/blog/how-to-autoload-with-composer or this which is probably more what you are looking for https://phpenthusiast.com/blog/how-to-use-packagist-and-composer A great resource for composer - https://getcomposer.org/ Composer has been around for awhile.
  11. /* if(isset($_GET['page'])) { $page = $_GET['page']; } else { $page = 1; } */ if ( isset($_GET['page']) ) { $current_page = $_GET['page']; } else { $current_page = 1; } $per_page = 20; // $num_per_page = 20; $offset = $per_page * ($current_page - 1) //$sql = "SELECT * FROM people ORDER BY id ASC LIMIT $start_from, $num_per_page"; $sql = 'SELECT * FROM people ORDER BY id ASC LIMIT ' . $per_page . ' OFFSET ' . $offset . '; I think this will work, but I'm just taking an educated guess. You are going to need know the total number of records, so that you don't go pass the total records in your database table using your previous and next links. HTH Helps? Though I do have pagination working on my own website - https://www.phototechguru.com/
  12. I would suggest to find a recent good online PHP tutorial or a recent PHP How-to-code book to get familiar with programming in that language.
  13. The best way to do that is to have a login to the secure area. Here's an example from my website - <?php require_once "../assets/config/config.php"; require_once "../vendor/autoload.php"; use PhotoTech\Resize; use PhotoTech\CMS; use PhotoTech\Login; Login::is_login($_SESSION['last_login']); Login::securityCheck(); and the class that check it: public function __construct($args = []) { static::$searchItem = 'username'; static::$searchValue = htmlspecialchars($args['username']); $this->password = htmlspecialchars($args['hashed_password']); } public static function username() { static::$searchItem = 'id'; static::$searchValue = $_SESSION['id']; $sql = "SELECT username FROM " . static::$table . " WHERE id = :id LIMIT 1"; $user = static::fetch_by_column_name($sql); return $user['username']; } public static function full_name(): string { static::$searchItem = 'id'; static::$searchValue = $_SESSION['id']; $sql = "SELECT first_name, last_name FROM " . static::$table . " WHERE id =:id LIMIT 1"; $user = static::fetch_by_column_name($sql); return $user['first_name'] . " " . $user['last_name']; } public static function securityCheck() { static::$searchItem = "id"; static::$searchValue = $_SESSION['id']; $sql = "SELECT security FROM " . static::$table . " WHERE id=:id LIMIT 1"; $result = static::fetch_by_column_name($sql); /* * Only Sysop privileges are allowed. */ if ($result['security'] !== 'sysop') { header("Location: ../game.php"); exit(); } } // more code..... It's my own personal website and I'm no security "expert", but I feel it pretty secure in what I do. Something like that will keep people from accessing those pages.
  14. $file_name = $_FILES['gambar']['name']; // Original File Name: $file_size = $_FILES['gambar']['size']; $file_tmp = $_FILES['gambar']['tmp_name']; // Temporary file for the directory: $file_type = $_FILES['gambar']['type']; $file_ext = strtolower(pathinfo($_FILES['gambar']['name'], PATHINFO_EXTENSION)); /* * Set the path to the correct folder */ $dir_path = 'folder/pda-semakan/gambar/'; /* * Create unique name for file. */ $new_file_name = $dir_path . 'file-example-' . time() . '.' . $file_ext; move_uploaded_file($file_tmp, $new_file_name); I didn't test this out, but you would do something like the above. Note $new_file_name would also store the path in the database table, so if you just want the just file then just out the $dir_path after saving the file to the directory.
  15. You can resolve a lot of those issues by using an autoloader (I use composer's autoloader) and namespaces. That way you can ensure there are no conflicts amongst your classes 99 percent of the time. Here's an example in what I'm talking about. <?php /** @noinspection ALL */ namespace PhotoTech; use Exception; use JetBrains\PhpStorm\Pure; use DateTime; use DateTimeZone; class CMS extends DatabaseObject { protected static string $table = "cms"; // Table Name: static protected array $db_columns = ['id', 'user_id', 'thumb_path', 'image_path', 'Model', 'ExposureTime', 'Aperture', 'ISO', 'FocalLength', 'author', 'heading', 'content', 'data_updated', 'date_added']; public $id; public $user_id; public $page; public $thumb_path; public $image_path; public $Model; public $ExposureTime; public $Aperture; public $ISO; public $FocalLength; public $author; public $heading; public $content; public $date_updated; public $date_added; <?php require_once 'assets/config/config.php'; require_once "vendor/autoload.php"; use PhotoTech\CMS; use PhotoTech\Pagination; /* * Using pagination in order to have a nice looking * website page. */ $current_page = $_GET['page'] ?? 1; $per_page = 2; // Total number of records to be displayed: $total_count = CMS::countAllPage('blog'); // Total Records in the db table: /* Send the 3 variables to the Pagination class to be processed */ $pagination = new Pagination($current_page, $per_page, $total_count); I'm not saying that's the issue, but it will save you a lot of headaches trying in having to rule out conflicts.
  16. Yeah I know, but wouldn't the file name have to be known if it is a hidden attribute?
  17. if ($_FILES['image']['size'] >= 44040192) { $errors[] = 'File size must be less than or equal to 42 MB'; } Simply check the file size and throw and throw an error if it is too big. I would also on the HTML page state the maximum file size allowed to upload. You could also try to compress the file, but that gets more involved.
  18. SwiftMailer is also another good one, I use it and it's very simple to use and has good community support: Just a small section of a small script /* create message */ $message = (new Swift_Message('A email from ' . $data['name'])) ->setFrom([$data['email'] => $data['name']]) ->setTo(['example@email.com']) ->setCc([$data['email'] => $data['name']]) ->setBody($data['message'], 'text/html') ->attach(entity: Swift_Attachment::fromPath('https://www.example.com/assets/images/img-logo-003.jpg'));
  19. Well, the path won't be "hidden" even if you get it to work properly as anyone can get the path by looking at the HTML once the image is displayed. That is if I am understanding you properly?
  20. require 'initializations.php'; if(isset($_POST['add_cat'])) { $cat_obj->add_category($_POST['cat_title']); header("Location: admin/category.php"); exit; } To me there should be some kind of check to see if the add_category method/function to see if it actually did what it say. The way it's written now it blind faith that it worked and the reason for the header redirect? This is what I'm talking about require 'initializations.php'; if(isset($_POST['add_cat'])) { $result = $cat_obj->add_category($_POST['cat_title']); if ($result) { header("Location: admin/category.php"); exit; else { echo "Oops, something went wrong"; } } of course something in return true or something like that needs to be in the add_category. If require "header.php" is causing the problem then maybe the above needs to be in a configuration file or sessions needs to be used? As the above then isn't at the level at should be at.
  21. That's also true for grid elements as well.
  22. Well, if you just update the $_SESSION on page1 directly, but go straight to page 2 then how is it going to update? It will update if you go to page 1 first then page 2. I hope I'm making sense? You need to update it in a configuration file of some sort or it as a set option where you can't go to any other pages if you update ppp?
  23. Hmm? I didn't not know that as I'm a iPhone user. I find it strange that android devices would do that. I think a work around would to check the email.value to see if it's empty?
  24. Well, I would if the errormessage is the trigger then just wipe out the input value (email.value = "";) for the email, have it required and show the error message. HTML5 won't allow a user to proceed. Maybe? if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) { errorMessage = 'Email contains invalid character/s'; email.value = ""; } Though it really isn't checking totally for invalid characters just the proper format. (That's what I'm concerned about) I think most people are pretty careful in typing their email address.
  25. const emailIsValid = (email) => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); }; email.addEventListener('change', () => { let status = emailIsValid(email.value); console.log('Email Address', email.value, 'Status', status); if (!status) { email.value = ""; email.placeholder = "Email Address is Invalid!"; email.style.borderColor = "red"; email.focus(); } else { email.style.borderColor = myBorder; sendEmail.email = email.value; sendStatus.email = true; } }); It's still best to check it server side and HTML5 make it required.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.