Jump to content

gizmola

Administrators
  • Posts

    5,954
  • Joined

  • Last visited

  • Days Won

    145

Everything posted by gizmola

  1. My suggestion would be to look at the template code, and look at what happens when you navigate to http://mentalhospital.rf.gd/index.php?/recent_pics. Whatever querying is done for that, you want to add some of that logic to the default/homepage section of code so that it selects however many pictures you want in this block. Then you'll need to edit the home page template and add this new block in whatever way you want. Like most packages of this sort, you have to go in and edit the theme file(s) to customize it beyond whatever customization options the package offers, which in this case, it appear are few.
  2. Each method or function should do one thing. You have lots of redundant/competing object instantiation going on. Think about what your classes do/are for. What purpose do you need. You also seem to have a basic misunderstanding of how class properties are available/used. 1st things 1st. One source file per class. Only the namespace statement and class code. The filename should match the classname. Once you get the hang of this things will start to come together quickly. 2 Things you can learn more about to upgrade your code/understanding of PHP Oop. Learn about PHP Namespaces. Start using them. Add composer to your project mix with an initial composer.json. PHP Namespaces: The basics of them PSR-4: How to name your classes and organize them in your source tree to match, so they can be autoloaded Using Composer for package management and autoloader generation Learn about Dependency Injection as a design pattern. This was suggested to you previously. A blog series on DI by Fabien Potencier, creator of the Symfony framework project To do PSR-0/4 compatible namespacing, you need an orgname. It doesn't matter what it is, but case matters. So for example, let's say you were writing things for Phpfreaks, and the team decided all code would use that as the organization name. Then the Top namespace is going to be Phpfreaks. In this example, Somename is a stand in for whatever you want to use for your code. Let's try a new Db class: <?php // Filename /src/Database/Db.php // In composer.json you will have a PSR-4 mapping for Somename mapping to your project src directory. You will place all your classes in directories beneath src, organized as you see fit. namespace Somename\Database\Db; class Db { private $host; private $dbName; private $user; private $pass; private $charset; private $pdo; public function __construct($host, $user, $pass, $dbName, $charset="utf8mb4") { $this->host = $host; $this->user = $user; $this->pass = $pass; $this->dbName = $dbName; $this->charset = $charset; $this->connect(); } protected function connect() { try { $dsn = "mysql:host=".$this->host.";dbName=".$this->dbName.";charset=".$this->charset; $this->pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); } catch (PDOException $e) { echo 'Error: '.$e->getMessage(); } } public function getConnection() { return $this->pdo; } } Before instantiating your Data class create a new instance of a DB class, passing in all the parameters to the constructor. In this example, charset is optional. The constructor will try to make the pdo connection. <?php use Somename\Database\Db; use Somename\Database\Data; $db = new Db('localhost', 'user', 'pw', 'database'); // Data class should store the $db parameter in a private variable in the constructor. $data = new Data($db); Then from within data you could be using $this->db for pdo connection related things.
  3. It seems like a pretty good design, however, having a Logo page with an image is kind of old school, and not accessible. You should have an alt tag at very least. You want to go over all the accessibility features and make sure you've implemented them properly. The front page of the site spacing could use some margins so your form elements don't bunch together quite as much. The actual results are ok. Having everything centered doesn't look great to me. I would probably suggest either a table or perhaps a ul. It's odd to see a paragraph with all the text center aligned so that the 2nd line with 5 words is in the middle of the first one. Again I'd fine tune the markup and css a bit, and perhaps have some subtle background colors and borders around the various result boxes, to make it look a little bit nicer. The pre tag for your whois information is not responsive. Styling it this way would probably be helpful. pre { white-space: pre-wrap; word-wrap: break-word; text-align: justify; }
  4. Yes, although again the UI is incorrect. Checkboxes are not mutually exclusive. So you are just doing this UI in the wrong way. Your form code is also wrong. You have a label that is hardwired to dark, yet you have variables toggling the value from light to dark. When a form is rendered, it should always be checked, because you are using the checkbox to toggle from light to dark. This means that a value for the checkbox will never be set in the way you using this. A newly rendered form will always have a value (light or dark) and will be checked. Once you uncheck it, you'll submit the form, and the checkbox will not be passed. However, to your question, you have 2 choices: Write a little js that checks the check/uncheck state and sets a hidden element, which you use on submit Just have php check for isset() or use array_key_exists. If ! isset() then it was unchecked. You want to check the request method to make sure the form was actually posted. Not that I'd advise this, but in this case, and again you have to be logical and clear, if the form is submitted, then you are looking to toggle the value. <php if ($_SERVER['REQUEST_METHOD'] == 'POST') { $mode = empty($_COOKIE['mode']) ? 'Light' : $_COOKIE['mode']; //Toggle it $mode = ($mode == 'Light') ? 'Dark' : 'Light'; setCookie('mode', $mode); } else { $mode = empty($_COOKIE['mode']) ? 'Light' : $_COOKIE['mode']; setCookie('mode', $mode); } // Now can use $mode to render ?> <input type="checkbox" onChange="this.form.submit()" value="<?= $mode ?>" name="mode" checked> <label for="mode"><?php echo "$mode Mode"; ?><label><br> Again when you think about it, the actual value of the checkbox is irrelevant as you are really going to toggle the cookie value on any submit. The other option is to use some js. Probably what I would do is use a hidden field, so that you could rely on the submission, but then when you have a cookie you are also relying on, this whole scheme makes less sense Something like this could work: <?php if ($_SERVER['REQUEST_METHOD'] == 'POST') { $mode = empty($_COOKIE['mode']) ? 'Light' : $_COOKIE['mode']; //Toggle it $mode = ($mode == 'Light') ? 'Dark' : 'Light'; setCookie('mode', $mode); } else { $mode = empty($_COOKIE['mode']) ? 'Light' : $_COOKIE['mode']; setCookie('mode', $mode); } ?> <!DOCTYPE html> <html lang="en"> <head> <title>Form Test</title> <script type="text/javascript"> function toggleMode() { let cb = document.getElementById("cbmode"); let newMode = document.getElementById("new_mode"); newMode.value = (cb.value == "Light") ? "Dark" : "Light"; console.log(newMode.value); document.getElementById("modeForm").submit(); } </script> </head> <body> <form id="modeForm" method="post"> <input type="checkbox" onChange="toggleMode()" value="<?= $mode ?>" id="cbmode" name="cbmode" checked> <label for="cbmode"><?php echo "$mode mode"; ?></label> <input id="new_mode" type="hidden" value="<?= $mode ?>"> </form> </body> </html>
  5. The biggest changes in the PHP world: Additions to the PHP language Deprecation of MySQL_ Addition of namespaces and PSR-1/Now PSR-4 Creation of Composer and packagist Ascension of git to standard (Github, Bitbucket, Gitlab) Big 2 MVC frameworks (Symfony/Laravel) Vast improvement and adoption of Component libraries, installed via composer Explosion of cloud computing/hosting The biggest changes to methodology: Move to using Docker & Docker-compose for development Use of Git For editors, most pro developers are using phpStorm. It's the best PHP IDE, and the one you most commonly see being used. Visual Studio Code is pretty competent, and is free. There are a few PHP extensions that make it quite competitive to phpStorm, but you have to do some work in getting it setup. Both editors have great support for docker and git, although I tend to be a cli person, and feel more comfortable having a terminal open and multiple displays. They both have integrated terminals and you can basically stay in the IDE window 99% of the time, when iterating. As a long time user/early adopter of virtualization (Xen, Virtuozzo, VMware, Parallels, Virtualbox, Vagrant) I have used nearly all the virtualization and development orchestration options at one time or another, but at this point, Containers have proven to be superior for development, when compared to full OS virtualization, and have become the primary platform for deployment at scale. Given your stack requirements, Docker is a great solution, because you can easily iterate through the various versions and combinations of the stack under Docker, without having to build full virtualized OS's or install any packages. Just use the Official Docker images for PHP and MySQL. The PHP container already has versions of apache, simplifying your setup. Git is a great facilitator for an upward migration process, as you can make a new branch each time you go up a PHP version, fixing things you need to fix as you go, and allowing you to switch back and forth between branches or have multiple git clones where you could conceivably be running an older version of the app against an older stack, while simultaneously running a newer version that is in the development process. For getting bootstrapped into Docker, there are projects like Devilbox, Laradock, or even my relatively new project docker4lamp. These can all provide a basis for you to get comfortable with Docker and how to orchestrate containers together. I'd promote Docker4lamp more in terms of its stack matching your target, but the purpose of the project is to have a latest/greatest stack for someone relatively new, but with a solution to all the various problems that new developers confront at some point. Being far simpler in scope than either devilbox or laradock, it might be easier to learn from, as you may want to have your own docker images and docker-compose added to your source. Needless to say there is an incredible amount of information you can find to help you jumpstart your understanding and use of Docker. Of the 2 "kitchen sink" packages I mentioned, probably laradock (which despite the name, will give you a complete set of containers to work with) is going to be easier to get up and running with. Quality documentation exists for both projects. Once you have done all the porting work you need to do, you can decide if you want to deploy onto an OS with packages as you have been in the past, or use Docker in production under Kubernetes or docker-compose on linux. I also have been a longtime Centos user, and recently setup a hosted vps under Alma. The main thing I learned is that you want to use dnf and not yum, but otherwise it looks like Centos. I will say that for a long time, the Centos official packages had to be worked around, and people were using epel and remi to get anything close to current. It's really a pain, and yet another reason to consider just running containers instead. For a reverse proxy, one relatively recent option that has emerged is traefik. It's a really nice option, and far less complex to get going than nginx or squid or ha. With that said, usually scalability involves substantial architectural decisions and the avoidance of building in things that require a monolithic infrastructure. Step 1 would be getting your app current to a supported version of PHP. You might also want to upgrade your MySQL version to something fresher. Step 2. would be looking at performance/scalability, if there are any significant issues. Full disclosure, most of the projects I've worked on in the last 10 years have been deployed within AWS.
  6. An unchecked checkbox isn't passed when a form is posted. You could correct for that, or you could use a more appropriate form element (radio button or select list).
  7. Just looking at your design, the obvious missing piece is that you don't know when a particular award-skill is passed, so that's a benefit to the system, although maybe that isn't something you can manifest at this juncture. Looks like your new tables would be: StudentAwardSkill ----------------- person_id award_id display_ord date_skill (optional) You need a unique index on (person_id, award_id, display_ord) The scary thing about the current design, is that if anyone were to modify the display_ord value of any skills, it would basically change/corrupt the entire meaning of any stored Skills in the StudentAwardTbl.skills column. You might be wondering how you can build the bridge I described: Your new app should only be concerned with writing out the proper relational design - writing rows to StudentAwardSkill. Your checks = UPSERT (typically use INSERT ignore.) You attempt to insert a new row for every checkbox using person_id, award_id, display_ord. Set date_skill to now() if you want to use that. The main issue with this design is the handling of "unchecked boxes" . An unchecked box means that you need to issue a delete against StudentAwardSkill, again for that person_id, award_id, display_ord combination. You will need a table named something like AwardSkillSync AwardSkillSync --------------- awardskillsync_id created_on (timestamp) changeby (tinyint) student_id award_id processed (tinyint, default 0) When your endpoint runs, you create a row in AwardSkillSync, with changeby = 1. StudentUpdateTrigger runs when StudentAwardTbl.skills is changed. Creates an AwardSkillSync row with changeby = 2 row. Now you are only left with writing a sync command line script. That script should query for oldest rows with processed = 0. It should SELECT for update, and depending on the changeby it will either look at the flags in StudentAwardSkill and conform the values in StudentAwardSkill to what is in that array OR query the values from StudentAwardSkill, and generate the string, updating it. If there are few users and few updates, most likely changes will be synchronized in either direction in what appears as near instantaneous fashion. There will be extra queries needed when a change is made in the old delphi system, but that is the cost to being able to have this bridge with no changes to the existing delphi system. The important thing to keep in mind for this to work, is that your sync routine should not update StudentAwardTbl.skllls if things are already correct. Just mark the row as processed. Although a bit less important, as no trigger is involved, would be any updates to StudentAwardSkill. Once the sync worked for either update, you could put it in a cron that you could run every second. You want to make sure that you use some type of semaphore that would prevent the job from running if another job was already in process.
  8. Systems are often hamstrung from the get-go with bad database design decisions. Since you are doing this for a charity (and I assume, donating your time?), I really don't see any reason to force yourself to build upon a poorly designed system. If you're doing this in part to hone your skills, then there's even less reason to reinforce a bad design, by building something new against it. There is a way to continue to use both systems, which is to create the tables you should have, then develop some bridge code that will keep them in sync. It's not simple, but it can be done, and then you won't be stuck with the mistakes of the past forever. As for updating in page, the answer is to use ajax. Have the button click submit values to an endpoint you develop that take the changes and modify the data as needed. Modern ajax code should be written using ES6 and best practice techniques: Use Fetch with promises (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) Pass data to/from your ajax endpoint in json format I don't know what version of bootstrap you are using, but resist the temptation to utilize jquery for this stuff, even though jquery does have the $.ajax() call, which could be used. As for your PHP endpoint, just think of it as the same script you might write if you had a standalone form that was submitting only the data you need to do this update. You will want to read the data from POST, json_decode it, and from there the actual processing should be straightforward.
  9. As an aside, Light/Dark themes are a great use case for SASS/SCSS. Here's a short article to illustrate some of the ideas.
  10. Hey I didn't name the field 😅 But my american upbringing says that "specialty" is good. I do like the english pronunciation of spe-cee-al-it-tee of your version though.
  11. My First comment: Don't use enums. I would recommend changing the definition of the field to a CHAR[1], and store either a 'P' or an 'S'. Your code should not interpolate values into your SQL even if you are escaping them. Use Prepared Statements. Your redirection code should be changed: if ($specialty == "pro") { header("Location: pro.php"); } elseif ($specialty == "stu") { header("Location: stu.php"); } else { die('Unknown Specialty.') } Note format of the Location header.
  12. I already debugged this for you. Did you use the code I posted? It was tested, and doesn't have any bugs involving the $ques variable being undefined.
  13. It was something I used to test out a docker project I've been working on, so it really didn't take long. Gave me an excuse to play with it.
  14. I used your database structure and values. You have an issue with the data in quiz_answer. I am going to leave it to you to figure out what is wrong (Hint: the answers need to match the correct option_id!) Here are the files I used. You will need to have valid database host, name, password and db variables defined in the quiz class, so that you are connecting to the database. One thing you need to understand is that when you submit a form ALL the fields in the form are submitted, including buttons. Everything will be in the $_POST array. I added a line of code to deal with this problem. I also added some code to display the grading step for each question, so you can better understand what is happening. Some good functions you can use to help you with simple debugging: When you don't understand what a variable contains try adding print_r($variable);die(); This will show you the value of the variable and stop processing. You don't have to stop processing, but having a lot of these statements is often confusing. Solve one issue and move on to the next. The biggest issue with this code is the use of numeric indexing of your mysql data with mysqli_fetch_all. Things would be better if your mysqli fetch routines used mysqli_fetch_all($result, MYSQLI_ASSOC); Working with array keys is much clearer, not to mention safer than having code like: (if $somevar == $array[0][2]). That code would be something like $somevar == $array[0]['option_number'] instead. //quizclass.php <?php class Quiz { // Database credentials private $host = 'hostname'; private $username = 'username'; private $password = 'password'; private $database = 'dbname'; public $db; public function __construct() { if (!isset($this->db)) { // Connect to the database try { $this->db = new mysqli($this->host, $this->username, $this->password, $this->database); } catch (Exception $e) { $error = $e->getMessage(); echo $error; } } } public function get_questions() { $select = "SELECT * FROM `questions` where is_enabled = '1' "; $result = mysqli_query($this->db, $select); return mysqli_fetch_all($result); } public function quiz_options($qid) { $select = "SELECT * FROM `quiz_options` where qid = '$qid' AND is_enabled = '1' "; $result = mysqli_query($this->db, $select); return mysqli_fetch_all($result); } public function answer($qid) { $select = "SELECT * FROM `quiz_answer` where qid = '$qid' "; $result = mysqli_query($this->db, $select); return mysqli_fetch_all($result); } } //index.php <html> <head> <title>PHP Multiple Choice Questions and Answers</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> </head> <body> <?php include 'quizclass.php'; $db = new Quiz(); $quesions = $db->get_questions(); ?> <div class="container"> <h1>Multiple Choice Questions Answers</h1> <p>Please fill the details and answers the all questions-</p> <form action="score.php" method="post"> <?php foreach($quesions as $ques) { $options = $db->quiz_options($ques[0]); ?> <div class="form-group"> <h4><?php echo $ques[1]; ?></h4> <div class="input-group-text" style="text-align: left; font-size: 18px;"> <ol> <?php foreach($options as $option) { echo "<li><input type='radio' name='".$option[1]."' value='".$option[0]."'> ".$option[2]."</li>"; }?> </ol> </div> <?php } //end foreach ?> <div class="form-group text-center"> <input type="submit" value="Submit" name="submit" class="btn btn-primary"/> </div> </form> </div> </body> </html> //score.php <?php include 'quizclass.php'; $db = new Quiz(); $score = 0; foreach ($_POST as $k => $v) { if (is_int($k)) { $answer = $db->answer($k); if ($answer[0][2] == $v) { // option is correct echo "Question {$answer[0][1]} was correct.<br>"; $score++; } else { echo "Question {$answer[0][1]} was wrong.<br>"; } } } $score = $score / 4 *100; if($score < 50) { echo '<h2>You need to score at least 50% to pass the exam.</h2>'; } else { echo '<h2>You have passed the exam and scored '.$score.'%.</h2>'; }
  15. Look at your original post. The code for the 3 files is your original code, with edits by me. In particular the index.php code was very broken and I made changes to that. I don't guarantee that any of the code works, but I fixed obvious problems. Take the code from each block and replace the code in your original files, and test.
  16. It wouldn't hurt to learn a bit about the basics of HTTP protocol. GET Method passes all parameters on the URL. POST Method passes parameters in the request body. This is 2 totally different ways of passing data from a form to the "target"/receiving script. PHP hides complexity in its page processing by bundling up the passed url parameters ($_GET) or variables in the request body ($_POST), but in either case, you need to understand the method the form used to call the script that is receiving data. If a form tag doesn't specify a method, data from the form will be passed using the GET method. Conversely, if you specify the method of the form to be either GET or POST, then you will want to check either $_GET or $_POST. In PHP there is actually a sort of cheat, which is to check $_REQUEST, which php builds with the same data regardless of whether the data was sent by GET or POST. <form action="somepage.php" method="get"> <label for="fname">Search:</label> <input type="text" id="search" name="search"><br><br> <input type="submit" value="Submit"> </form> vs <form action="somepage.php" method="post"> <label for="fname">Search:</label> <input type="text" id="search" name="search"><br><br> <input type="submit" value="Submit"> </form> Notice the method? The reason it didn't work when you checked $_GET[] was that your form had method="post" set. Creating 2 identical scripts to do searches, because you didn't understand this very basic concept in regards to how html forms work, is not a good way to maintain or enhance your system.
  17. For Docker under windows, you don't have to use Hyper-V, you can simply install the Windows Subsystem for Linux (WSL) More info here: https://docs.docker.com/desktop/windows/install/#wsl-2-backend
  18. phpmyadmin is just a php application. Check a phpinfo(), or from the command line run php -i and see if those extensions are available/enabled. Mysqli, in particular has to be installed. With that said, there seems to be some confusion, because on one hand you are talking about running a phpMyAdmin installation, and then you are providing errors by the command line tool composer. Are you running composer in order to install something?
  19. You can clutter your workstation up with a bunch of services with WAMP, or you can use vagrant or better yet Docker. Most developers are using Docker now. My advice is to install Docker and look for a tutorial that will help you get a LAMP development environment up under docker, using a docker-compose.yml.
  20. I don't know if you have a question here. In the future post code using the code tag button. Some things I did when fixing your post: Your index.php had a number of errors in the way the form markup was rendered. You were also missing a php block end brace. When you have a class file like the one you have for Quiz, then name that file Quiz.php. I didn't change that in your code, but you should follow that practice going forward. You probably want to replace the code you had, with what I put into your post (which I edited heavily). If you have an actual question, you can follow up in this thread.
  21. No, html4 and xhtml were predecessors of html5. Nobody uses those anymore, and while pages authored with those doctypes still work with most browsers, you should ignore them entirely. Just use html5! There are indeed a number of free webhosting services. Really you get what you pay for, and I wouldn't recommend using any of them if you can avoid it. If you can afford a from $3,$5 or $10 a month, there are many shared and even cloud service options. I would try and avoid shared hosting, and go for a vps(virtual private server) which will allow you to learn a lot more about website development and deployment. With a VPS you have full root access and the keys for your server, as if you were running your own machine in a data center. You ssh into it, and can do all the setup and administration of your site yourself. In the process you will learn everything there is to know about web development, system administration and site hosting. Another reason to avoid shared hosting is that for most of them having HTTPS/SSL on your site (which all sites should have now) is an often expensive upgrade in service, whereas, anyone can now get free SSL Certs, and maintain those using Let's Encrypt and the installation of Certbot. Amazon AWS has a 12 month "Free tier" where you can deploy on an ec2 micro instance. You get access to the majority of their services and can learn about the world's largest cloud services provider. Vultr is a cloud provider who is currently offering a $150 credit. They are often compared to the company I have used for many years, Linode. Both are mid size cloud service companies, so they have more options than a lot of the smaller vps hosting companies. Their base vps is $6 a month. You do have to pay an initial $10 which goes as a credit, but basically with $160 worth of credit, your $6 vps will be free for a good long time while you host and learn. I don't know how long this $150 credit offer will go for. Another thing that differentiates Vultr which you might like is that they have data centers in Europe, with one in Sweden. I'd personally suggest opting to host your site there, as it will be closer to you, and your day to day work with your vps will be faster. Hostinger is one of many even lower cost hosts, that have comparable entry level vps's for lowcost. Hostinger has a good reputation, and I think the low cost one is $3.95/month. There are many other options if you want to price shop. Try googling "best cheap vps" and look through some of the articles and offerings. Again make sure, you are looking for a VPS and not a shared hosting account. They are cheaper, but frequently limit you significantly, which isn't what you want as a student and developer in training. You will get a lot of opinions on this, but I would suggest that if you set up a vps somewhere, opt for either Alma or Rocky linux, which are both what Centos used to be. Most VPS's default to running Centos, but Centos is being phased out, so you want to start with the latest Alma or Rocky, and they will work exactly as Centos (which is just Redhat Enterprise Linux, aka RHEL).
  22. When you do authentication, keep the status of the authentication in the Session. There is nothing more or less needed. The way the session connects to the user is through the session id, which should be configured to only be passed via HTTPS and stored as a cookie. You write a generic function or method that reads the user information from the session. No user state -> redirect to login If you have some sort of login duration you want to enforce and it's expired, you can also look at that and redirect If the user wants to "escalate" which involves anything having to do with gaining additional access or changing key things in their user/profile, like email, password etc. you reprompt for their password You can put this logic into a class, or add to the user class, and once you've perfected it, every routine that requires authentication should pass through this routine first, to determine if the user is logged in. This includes ajax routines. In those routines you can pass back an error state indicating the user is not logged in, or whatever you want your ajax error information to contain.
  23. So to be clear, you have no security concerns in your app? It is ok with you that anyone can pass the userLoggedIn parameter to your ajax api call endpoint and see the posts for that user?
  24. If I understand the basics here, then this code should create the reservation? $reg_Traslados = new reg_Traslados($dt->getId_traslado()); So you need to do some debugging of the reg_Traslados class and attempt to figure out what is going wrong when the user selects one way, given that nothing gets created in the database.
  25. Let's try again. What is the code in pro.php? For the "form" script, how and when does that get called? Is this a user system, where a user can change things in their profile? What is your design goal? Do you want the form to always be populated with the existing data? Where do we get the existing user data from? Does it need to be queried from the database? Let's assume your profile page with form, has queried all the user profile data from the database and stored that in an array variable named $user, with array keys for the fields. Then your form code would be something like this: Bio: <input type="text" name="bio" size="40" <?php if (!empty($user['bio']): ?>value="<?= $user['bio'] ?>" <?php endif; ?>>
×
×
  • 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.