-
Posts
5,960 -
Joined
-
Last visited
-
Days Won
146
Everything posted by gizmola
-
I made an app that uses DBAL to do this, as a quick and dirty proof of concept. Anyone with an interest can check it out here: row cloner Took less than a day start to finish, including learning enough about Bulma to get a decent looking UI put together.
-
You really want to focus on the ones that are programmatic. This is why using a template system like twig or even (back in the old days) smarty is so valuable. Typically this is because you have some sort of database structure where you are entering and configuring attributes related to a page. The title tag is the prime example, even though it is not a meta tag. You also should have a canonical link for all pages, even when that is on a canonical page (pointing back to itself). For example, if you look at the yahoo home page, you find this in the head. <link rel="canonical" href="https://www.yahoo.com/"> As for the meta tags they have the general form of (name, content) so a helper function could be: function makeMeta($name, $content): string { return '<meta name="' . $name . '" content="' . $content . '">' . PHP_EOL; }
-
Google by far generates the most organic search traffic, so it's best to focus on them, as most of the other search engines follow their lead in terms of how they score a page internally. Also the google search console is an excellent tool for getting an idea of what is going on with the indexing of your site. You should make sure you've gone through the steps to insure that every site you control is registered within the tool. The title tag is important. There's a rule of thumb being "12 words/70 character max". Google indexes only the 12 words, weighted towards the first 12. It will also only display up to 70 characters. The description tag is important, only so much as it will be displayed when it comes up in a search result. This is where you can "sell a user" on the relevancy of that page, since the description will show up with the result. Keywords and description are both things that google no longer uses, and were used in the past by people trying to game SEO, by putting in descriptions for pages that don't have relevant content to match the description, or a long list of keywords they "wished" the page in question was relevant for. Any decent search engine these days, parses the content of the page and uses a high degree of sophistication in determining relevance. You aren't going to fool anyone by listing a bunch of key words in the meta tag. Since Google hasn't even looked at them in years, many sites omit them at this point, and if that was a significant concern, you would see discussion of that. Typically if you look at SEO discussion, the main thing that comes up beyond proper use of meta tags is h1's, canonical vs. non-canonical versions of a page, and how to handle those, and having a sitemap (that you re-generate/add to whenever you add a new page to your site.) For indexing pages and internal link collections (for example a page on a blog that has all articles for a particular year, or a page in a catalog where you have all products within a particular category, the robots tag is a good one, and has advantages over using a robots.txt. You don't want non canonical versions of the same page, or pages that could lead to indexing of a non-canonical version along with the canonical version as this has the potential to reduce the overall score for the canonical page. Pages like that should typically include the robots tag. <meta name="robots" content="noindex, nofollow" /> More about that here. If you have video content then you want a video sitemap or mrss feed as described here I know that not all of this is directly related to your meta data question, but hopefully still generally related and useful.
-
Search engines just look at the final http response data. They have no visibility into the internals of how a page is rendered. There is no problem doing what you want to do, and in fact many cms's, forums and frameworks do this exact thing. Just to be clear, meta tag keywords are ignored by google, so you may or may not want to include those in your page rendering.
-
Is it possible to pass multiple variables through one method argument?
gizmola replied to chesse18's topic in PHP Coding Help
Since I'm more of a symfony guy, symfony has something very similar: webpack encore. -
Yeah, certainly it's typical to have a whole set of relations you want to clone in most cases, so the entire premise here is simplistic, but an interesting challenge as is. DBAL provides an interesting option, where it will expand parameters. I'm playing with that at the moment, just to see how simple an app could be to do this somewhat generically.
-
I didn't think about doing it wholly with PHP, but yeah, that is a good way to do it in this circumstance. Just 2 queries, even though you have to read the result -- it's 1 row. The main concern I would have, never trying this, is that the columns must be in the correct order. You'd also have to escape the strings. It's a bit tricky, unless I'm missing something.
-
When you try to run on page load..... what? Typical jquery loading would be in the document ready: $(document).ready(function(){ $("#staticbackdrop").modal('show'); });
-
Yeah, really makes me wonder what this is for. I'm guessing it's some sort of home grown development/test tool to clone an existing row. Under the circumstances, I don't see a better way of doing it, as there's no non-trivial way of getting all the columns other than id that doesn't involved either something like this, or querying table definition from the information schema and using that to generate a sql statement. I'd suggest adding ENGINE=Memory for the temp table definition. Also you don't have to drop the table, as it will be dropped when the connection is closed. That is the point of declaring a table as temporary.
-
Is it possible to pass multiple variables through one method argument?
gizmola replied to chesse18's topic in PHP Coding Help
SCSS is some good stuff, and the built in compiler is a great time saver compared to setting up webpack. Active Record: not a fan of it honestly. Seems nice at first, but the more you use it, the more limiting and kinda dumb it is. Data mapper pattern is far superior in many ways, I won't go into, but to each their own. Worked on a project not too long ago (consumer service) where they used Laravel, and then Dev's spent a bunch of time adding things to Eloquent to add a home grown version of doctrine repositories. -
Is it possible to pass multiple variables through one method argument?
gizmola replied to chesse18's topic in PHP Coding Help
The analogy of comparing composer to react isn't correct in my opinion. More like composer = npm. Every project should have a composer.json file in my opinion. Takes 2 seconds to make, and will provide you config for an autoloader and a correct way to namespace and place your classes, even if you don't use any others. Run composer init, answer a few questions and you are off and running. Also points you gently in the direction of putting your "public" (web accessible) files under public and not having pointing your webroot with a tree of all your files, which at best is a mess and worse a potential security issue. You include the generated PSR-1 or PSR-4 autoloader in a bootstrap or ideally a front controller. Could be as simple as something like this: if (!defined('ABSPATH')) { define('ABSPATH', dirname(__FILE__) . '/'); } require_once(ABSPATH . "../vendor/autoload.php"); At some point with any web app, you might want logging, or a mailer, or file handling, routing or a simple HTTP request/Response class. With 5 minutes you literally are up and running with unit tested code in most cases. The Symfony components alone have an extensive list of well designed time saving classes. -
Yes, it just isn't valid if you also use an ORDER BY, at least until 8.0.12.
-
Is it possible to pass multiple variables through one method argument?
gizmola replied to chesse18's topic in PHP Coding Help
I have never heard of this. Are there some questions you can link that illustrate what happened to you? I have a decent amount of rep from answering questions at SO, but I have noticed that the php zealots have taken over with their mission of closing any question that remotely resembles one that might have been asked in the past, so it's very hard for inexperienced people to have a question that isn't closed in short order. It's ironic that they say they want new users, but the mods involved in looking at php questions seem to think that there only mission is to compress everything down to previously asked questions at this point. Candidly, I don't see any advantage to your class over mysqli or PDO by itself. Since the class is useless without a database connection, that tells you you should at very least have a constructor that requires a db connection, rather than a separate startConnection method with a parameter that doesn't actually start a connection -- just dependency injects a connection resource which you depend upon in order for any of the code you have to work. Looking at the semantics, you wrote a couple of select query helper functions, that only work with the simplest queries possible. A decent wrapper around PDO that actually does offer some value for people is Doctrine DBAL. Doctrine is an Object Relational Mapping(ORM) component, used by the Symfony project to provide sophisticated relational database to php object mapping. It's an implementation of the Data Mapper pattern. In general, you tend to see that sophisticated OOP code is implementing OOP Design patterns that have been named. The link I provided gives you an idea of what the pattern tries to accomplish and some simple examples of how a particular pattern could be implemented. There's another ORM pattern you might have heard of called "Active Record" and has a number of framework ORM's which have implemented the "Active Record" pattern. CakePHP is a long standing one, and Ruby on Rails was a famous implementation of it. The Doctrine ORM depends on the "Database Abstraction Layer (DbAL) library, but DBAL can be used by itself and provides the same sort of things you are trying to provide. One thing to see is that the ORM's from the major frameworks across the board, have a query class which allows you to programmatically build up sql queries. This is really the heart of what you have focused on, only in a very limited and unsophisticated way. In comparison take a look at the documentation for the DbAL query builder class. Not trying to be a downer here, but there are a huge number of database classes available, with documentation and unit tests out there you can start using with little more than a "composer require name-of-package", rather than reinventing a restrictive wheel, that depends on the spread operator. -
Adding a count to a basic player with mysql and php
gizmola replied to PNewCode's topic in PHP Coding Help
So just to say it, the on event handler is accepting a callback function to run when there is a "play" event. A simpler solution would be to just have a function defined there, that the callback would run, or to define a function globally and pass the name of the function. However, @Kicken coded this function to return an anonymous function. It helps to focus in on return statements in code like this. If you notice the requestSent variable is declared outside the function declaration that does the work. This creates a "closure" (or takes advantage of javascript closure) depending on how you want to think about it. It makes the variable requestSent available to the inner function that is being returned, and this variable will continue to exist in the browser's memory associated with the window/page, until such a time as a new request is made that causes new html/javascript/css to be loaded. An alternative would be to declare requestSent globally and use that, but he gave you something more sophisticated -- a function that returns a function and takes advantage of a variable that is only visible to the anonymous function, and yet is available to the anonymous function across executions. Each time the callback is run, this could be either for the same song or a different song, so inside the function, there is a jQuery call to find the id of the button. let a_id = $(this).attr("id") It's good to think about why this is declared inside the function and how that works. Since this handler can be called for any song, the $(this) resolves in this situation as the song that is being played. Thus the a_id gets set each time there's a play event, and then gets the html id attribute. I added code to push the value onto the requestSent array, which again, since it's part of the closure for the anonymous function, survives across plays. I used Array.includes() to check if the song id already exists in requestSent. If not, I update requestSent with requestSent.push(a_id) and the ajax runs, passing a_id. The ajax is also being done using the jQuery library. The final question you should probably be asking is: if this is a function that returns a function, then how is it, that the callback, which requires a function to run, gets the actual function it needs. A function that returns a function is not a callback. The answer is that again Kicken used an IFFE here. What is actually being passed is a function that is immediately executed. You can see this because after the function definition function () { ... } It is immediately followed by the parens ie. () which causes javascript to execute the function. function () { ... }() So this code works because the function that returns a function, is run immediately, giving the callback parameter what it wants ... a function to run when a play event occurs. The function is anonymous and only bound to the event handler for play events, which also keeps global scope from being cluttered with a symbol table entry for a function that is only needed for the callback. The benefit of doing it this way is that he did not need to utilize a global variable, since closure takes care of this for you. This type of code is favored in many situations, since you don't have a slew of global variables floating around. Nothing outside the callback function can see or modify the requestSent array -- yet it is essentially a private environment that the callback uses. As I said previously -- advanced javascript stuff, that can be confusing if you are still learning javascript. Hope this helps -- using those terms (IFFE, javascript closure, js anonymous function, js callbacks, js this) will lead you to an enormous amount of additional material if you need to explore them further. -
@Strider64 I appreciate your long time presence and many helpful answers here, however in this case I have to disagree strongly with you. HTML id's should never represent anything other than a unique page element. That is possible with your example, in that there is only one question on a page, but that would be a very limiting design, once you decided to have 2 or more questions. A much better and more standard way of doing what you are doing there is to utilize data attributes. I'd probably expect to see something more like this these days: <div class="question-box"> <h2 class="question-box__question">What is the Question?</h2> <button class="btn question-box__answer" data-question="1" data-answer="1">Ans1</button> <button class="btn question-box__answer" data-question="1" data-answer="2">Ans2</button> <button class="btn question-box__answer" data-question="1" data-answer="3">Ans3</button> <button class="btn question-box__answer" data-question="1" data-answer="4">Ans4</button> </div> Here I employed BEM standards and data elements which match up with the type of scheme you might see in a database model that has a questions table and related rows in an answer table. Each button has all the data that's needed (the id of the parent question as well as the id of answer. In javascript you can get access to these values using the DOM getAttribute function, but even simpler than that the values are exposed as properties. So, assuming you are doing this in an onclick handler attached to the answer buttons, you can just get those values via the built-in dataset property. btn.dataset.question btn.dataset.answer This code illustrates how you would make this work with the markup changes I show above: function btnClickHandler(event) { console.log(`question: ${event.target.dataset.question}, Answer: ${event.target.dataset.answer}`) } let elements = document.getElementsByClassName("question-box__answer"); for (let i = 0; i < elements.length; i++) { elements[i].onclick = btnClickHandler } If you want to explore this further I made a Codepen of it.
-
I agree with kicken, but at least with MySQL there are some group by modifiers you can use with your GROUP BY queries, one of which is 'WITH ROLLUP'. With Rollup will produce additional summary value rows for each subgrouping. Of course to use this you need to understand how to identify these rollup rows when you fetch them. Since you only have one GROUP by in your case, there would be one final row with the total count, which you could take advantage of if you wanted to, as an alternative to using a PHP variable. Again, incrementing a variable in a fetch loop is a tried and true solution, but knowing about the group by modifiers is one more tool in your toolbox, which never hurts. You do need a fairly recent version of MySQL ( >= 8.0.12) to use WITH ROLLUP along with a group ORDER BY as you have in your code.
-
There's a lot to work through here, so I'll start with this: With CSS, always start with more general rules, then more specific ones. You have multiple embedded style blocks here, and I'm not sure why, but your general rules were added after the specific ones Keep in mind that styles "cascade" per the name. You don't need to re-declare all the attributes for a modification. Just use a modification class Many popular css frameworks like tailwind depend on this idea Getting familiar with a naming convention for css like BEM will help you create clear and logical css class names and avoid pitfalls and making your css inconsistent spaghetti It also will help you keep things clear. Use camel case for your PHP variables, and for class naming and general code formatting and style start with PSR-1 and perhaps graduate to PSR-12 It might not seem that important to you starting out, but it will help you get the most out of whatever editor/IDE you are using Most people are using either PHPStorm (the choice of most pro's) or Visual Studio code with the Inteliphense plugin installed If you go with vscode/Inteliphense make sure to read the installation instructions carefully and disable the built in plugin as directed Take a look at my changes to your css and html markup to see how I implemented these ideas on your code You rarely will want or need to use css id rules. ID's are reserved for a single instance on an page. For buttons, you are typically re-using those styles throughout the page, so use css classes for those and not id's Most css pros rarely/never use #name css styles. If this is tutorial type stuff, might tell you something about the freshness of the tutorial PHP code runs on/in the PHP server. It does not run in the browser like javascript code that is included or embedded in the html page. In other words, your PHP code will be run in response to a request, and returned immediately. You can intermix html and PHP blocks inside a php script, and that will work fine, but the PHP code needs to be in a PHP block, which starts with <?php As you should be able to see here, you have commented out all the PHP code you wrote using html comments. Thus none of that is going to run. There is an alternate syntax that can be used to make everything look a bit cleaner if you plan to do a lot of intermixing You can look up those options in the PHP manual. It allows shorthand for echo, and if - then -else type constructs and other PHP loop For superglobal array variable or array keys (or any other variable that may or may not exist) you want to check before blindly trying to utilize it. There are various language helpers that you can use to get around the situation where a variable doesn't exist. isset empty() function null coalescing operator Take care with PHP blocks inside if-then or if-then-else constructs. In general, it's a good idea to always make sure you have a block { ... } to handle each case. Your blocks don't look correct. Try not to chain if-then else, when instead you can use multiple if blocks. The code is easier to read and update in most cases. The issue with the code presented is that you have buttons but no form, so this invokes a lot of confusing default behavior and questions you might want to ask yourself like: Why/where is the form submitted? What type of submission is it? For example, if the type of submission is not a POST, can you expect $_POST variables to exist? I don't address these questions for you, but I expect you will need to figure them out soon. Here's some modifications to your code illustrating these thoughts: <meta charset="utf-8"> <title>Work intergrated learning</title> <style> body { font-size: 30px; } p { font-size: x-large; } .btn { padding: 10px; font-size: 20px; border-radius: 10px; font-weight: bolder; transition: background-color 2s ease Os; cursor: pointer; } .btn--submit { background-color: red; } .btn--submit:hover { background-color: green; } .btn--cancel { background-color: yellow; } .btn--cancel:hover{ background-color: orange; } </style> Rest of code... <p>Creating a button</p> <br> <?php if (isset($_POST['btn-atc'])){ echo 'You have added an item to your shopping chart'; } ?> <input type="submit" name="btn-atc" value="Add to Cart"> <?php $btnSubmit = isset($_POST['btn-submit']); if ($btnSubmit) { echo 'Your query has been successfully submited, our consultant will get in touch with you as soon as possible'; } $btnCancel = isset($_POST['btn-cancel']); if $btnCancel { echo 'You have cancelled your query.'; } ?> <input type="submit" name="btn-submit" class="btn btn--submit" value="Submit query"><br> <input type="submit" name="btn-cancel" class="btn btn--cancel" value="Cancel">
-
Please in the future use the <> button to insert your code blocks. Setting the language for the code block correctly is also nice. We can assume here you have some php script (maybe index.php?), so I set the blocks to be of type PHP. That causes PHP syntax highlighting to kick in, as it would in an editor. I will edit your post to insert those blocks for you this time.
-
Adding a count to a basic player with mysql and php
gizmola replied to PNewCode's topic in PHP Coding Help
Yes, so implementing kicken's suggestion, this should work probably: $('audio').on("play", function(){ let requestSent = [] return function(){ let a_id = $(this).attr("id") if (requestSent.includes(a_id)) { return; } requestSent.push(a_id) $.ajax({ url: "count-play.php?id=" + a_id , success: function(result){ $("."+ a_id + "count").html(result) } }); }; }()); Hopefully you understand what this code does, which makes use of some tricky javascript concepts, namely: Javascript closure An IFFE -
Fatal error: Uncaught Error: Class "mysqli" not found...
gizmola replied to Jagboy's topic in PHP Coding Help
Linux distros for the most part have their own package managers, and package developers who sometimes have schemes they are working with that differ from what another distro might use. Anytime you set up things on a different distribution you will likely encounter these differences and perhaps a problem or 2. I'm not sure why localhost wouldn't work, if you have a valid /etc/hosts file with an entry for it, but mysql also has a lot of potential configuration possibilities that change the behavior. By default it will use a unix socket, rather than trying to route through the network layer. Telling it to use 127.0.0.1 forces the client to try and use the network layer. This serverfault thread explores the issue and potential fixes. -
Syntax issues, still a newbie but getting there!
gizmola replied to Crazycabling's topic in PHP Coding Help
In general, if you have a static string with double quotes inside it, use single quotes. It's a micro optimization, but a good habit to start with, that you should always try to use single quotes, as they don't interpolate variables. If you don't need interpolation then go with single quotes. echo '<div class="btns">'; The problem with the code you presented is that you are inside a php block, so there is no reason for you to once again try and start a php block. It's not clear if you omitted anything however. If you were outside a PHP block and in "HTML" mode, then your code would work if you had simply echoed it. Since you are using alternative syntax that should work, but of course it will only work if the variable $_GET['id'] is not empty. To interpolate an array variable with single quotes, you simply need to enclose that entire variable inside curly brackets, which in essence tells php to perform evaluation of that variable and not treat it as a string that might require interpolation. However, in this case you also have a PHP string, so really all you want to do here in most cases is just use string concatenation. echo '<a href="viewtest.php?id=' . $_GET['id'] . '&status=Réouvert" class="btn blue" style="width:400px">Réouvrir ce billet</a>'; To use a heredoc echo <<<EOT <a href="viewtest.php?id={$_GET['id']}&status=Réouvert" class="btn blue" style="width:400px">Réouvrir ce billet</a> EOT; heredocs and nowdocs can be very useful when you have substantial amounts of html and php to be interpolated, although for one or two lines in mostly php code I probably wouldn't use it. -
Fatal error: Uncaught Error: Class "mysqli" not found...
gizmola replied to Jagboy's topic in PHP Coding Help
One other detail: I'm not sure what you mean by "tried mysqlnd". You should use mysqlnd, but that is the client library that mysqli depends upon, and should appear in the mysqli section of phpinfo. The other option is to use the libmysqlclient from oracle. The default since php5.4 has been mysqlnd. -
Fatal error: Uncaught Error: Class "mysqli" not found...
gizmola replied to Jagboy's topic in PHP Coding Help
I have never seen a situation where an extension showed up in phpinfo and yet didn't work. It would also be helpful to know what OS you are running on the device. Is this a cli program or through a web server? If you run a simple script like this, what does it indicate? <?php if (function_exists('mysqli_connect')) { echo "mysqli is installed"; } else { echo "Enable Mysqli support in your PHP installation "; } -
I'm not going to look at some old xampp tutorials and try and debug why they don't work, when it's pretty clear the answer is that the mysql root user has a password. Local installs like xampp have fallen out of favor for many reasons. People used to use vagrant, and now use docker. Either one would be better, not to mention closer to the environment into which you will deploy a finished app. MySQL has changed its password encoding schemes over the years, so if it's an old tutorial, it likely doesn't account for these changes. I realize it is localhost but it's just a bad habit to get into depending on passwordless database accounts. It's also a bad habit to use the root mysql user for non-administrative tasks. Figure out how to connect to the mysql database locally Typically this would be either through the mysql command line tool "mysql" or possibly through an installed phpMyAdmin app that xampp sets up for you. Here's what you should do through either one of those: create new database for your development create new mysql user with password and grant permissions to the new database for that user Update your connection code to use the user/password combination. One thing to understand about mysql that is non-obvious is that its security scheme is based on both user and host. grant all privileges on mydb.* to 'myuser'@'localhost' identified by 'mypasswd'; This assumes the root mysql user was used to create a database named mydb. Take careful note that these are single quotes, and not backtics. Notice the pattern of the quoting for the username. This command creates the user and sets the password and grants access to the database. Once you know you can connect to the database with either mysql cli tool or phpMyAdmin using those credentials you can expect your PHP code to work.
-
Adding a count to a basic player with mysql and php
gizmola replied to PNewCode's topic in PHP Coding Help
Hopefully this will simplify the whole ajax thing for you. 1st create a php script that will accept a POST request with a method to identify which row in the audio table needs to be updated This script needs to make a database connection and then issue an UPDATE query for that row The query is simple enough, something like: 'UPDATE audio SET pcount = pcount + 1 WHERE id = ?' You should use a prepared statement for this, where you bind the id parameter After the update, you can add a query to get the new count if you would like, and return that in a json form using json_encode. You will pass/get the ID parameter from the $_POST You can test this script independently using any testing tool that can generate a post. Postman is a good one, but if you use VSCode, then Thunderclient is an extension that will do the same thing, only integrated into VSCode, which is a nice option. Once you've tested your update script (which you might want to call something like "update_audio_playcount.php") you are ready to call this script via "ajax". Ajax is simply some javascript code you can call when your play button is pushed. You will need to populate your markup in some way so that you can get the audio row id value. Typically people use 'data-*' attributes to do this, so a good way of handling this would be to make sure the play button has an attribute like "data-song-id=x" which should make it very easy from javascript to get the id of the row in the audio table you need to update. Just to keep this simple, you can use the javascript fetch api to make your POST request to the update script. This example is from the MDN page I linked with a couple of modification hints you need for a form POST: // Example POST method implementation: async function postData(url = '', data = {}) { // Default options are marked with * const formData = new FormData(); formData.append('id', ... get the audio table id here and pass it); const response = await fetch(url, { method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, *same-origin, omit headers: { 'Content-Type': 'application/json' // 'Content-Type': 'application/x-www-form-urlencoded', }, redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url body: formData }); return response.json(); // parses JSON response into native JavaScript objects } postData('https://example.com/answer', {}) .then((data) => { console.log(data); // JSON data parsed by `data.json()` call }); The important detail we don't have is the structure of the audio table. Hopefully each row has an auto_increment id value, so that you can use that to identify the row that's needed.