Jump to content

gizmola

Administrators
  • Posts

    5,960
  • Joined

  • Last visited

  • Days Won

    146

Everything posted by gizmola

  1. The PHP process may not be able to write to the /var/log directory. Assuming it's the apache user that php is running as in this case. Connect to the container and check out the perms for /var/log.
  2. The first question I would have for you, is do you have a solid "non-expert" understanding of html5 and css? That is what I would highly recommend to get down 1st. This is a good free course to go through, that is all done interactively in the Scrimba environment: https://scrimba.com/learn/introhtmlcss It's taught by Kevin Powell who is one of the better known css teachers I know of, and has an extensive set of video tutorials on youtube. Before you go further down any path, I would recommend you watch this video, which really helps you get an idea of what these different techs provide you from a design/UI standpoint: If you watch enough of this you'll get to the point where he compares some options (vanilla css, vs tailwind vs Material UI (MUI) vs Bootstrap, and declares: "Yeah Don't use Bootstrap. It's 2022 and you know better!" Nonetheless, this is a professional design guy who has worked for various well known companies and is very experienced, so I won't be an absolutist about this, but you should at least go into whatever phase of learning you are entering knowing more about this. I personally use Bootstrap every week for a client I work for, and I would certainly love to be able to move on from it now, but I'm stuck with a giant code base that is tightly integrated with it. At least do your research. Absolutely you should be using the latest version if you do use it. I have found that it is actually pretty easy to use in most cases, however this guy has a complete course on it, and most of his videos are really good: One thing to keep in mind is that Bootstrap does have places where to really take advantage of some of the widgets, you also need to have a working understanding of javascript, in order to integrate it with what you are doing. That is going to be true of many other css frameworks and approaches. It also needs to be said, that whether or not you should be using Bootstrap is a significant question, as there are other css frameworks that have become extremely popular, most notably Tailwind CSS. There are a number of other popular css frameworks, many of which are better suited to customizing the look and feel of things, or have a philosophy that is a bit more modern than what bootstrap has (given that Bootstrap is pretty old at this point, even though it has been updated). Here's an intro to tailwind and a complete course by a guy who has a lot of courses on Udemy, and was actually paid to make a professional level course on Tailwind that is again free on youtube. It is project based, but only one project in this case. If you like Tailwind as an approach then you probably want to look at TailwindUI and/or DaisyUI which build upon Tailwind and are closer to what you would get with much of Bootstrap.
  3. There are functions and an entire database class you didn't include that is mysterious. Here's a simplified functional spec Initialize your variables, get initial statistics Get the largest timestamp value in the database. At the end you can use this to update any rows that need to be cancelled because there was no importer entry This assumes that every row has some sort of timestamp row. It appears that way, but you didn't provide the format. Import the file Check that there are entries. You don't want to cancel the entire userbase because the import was flawed Get pre-import statistics for active/cancelled One group by query for this will give you both numbers. SELECT COUNT(*) as count_of, memberStatus FROM Members GROUP BY memberStatus No need to pre-sort import data foreach through the import data SELECT id, status from Member where id = import id If row is found Based on ID, update status, timestamp If it's an actual datetime/timestamp you can do this with column = NOW() This guarantees that a found ID column gets its timestamp updated regardless of the status Based on status add to appropriate bucket rejoined was still status 1 if row not found Add new member Update to new member count When complete, SELECT COUNT(*) FROM Members WHERE "timestamp/updated" column is <= original timestamp you queried during initialization. These are the rows you now need to cancel, so store in your summary array as needed UPDATE Members SET status = 2 WHERE WHERE "timestamp/updated" column is <= original timestamp you queried during initialization At this point you should be able to make your final reporting. Count the arrays for new/ongoing/rejoined. Use the cancelled count# you got from the summary. You probably want to get an initial count of all existing rows via SELECT COUNT(*) but if all rows have a status of 1 or 2, then you can just use the counts from the GROUP BY query summed together.
  4. I'm not sure what you want from us, given an outline of your requirements and a basic list of steps. You know what you want to do, and the code doesn't work right or count right, so that means you have bugs. We can't debug your code without seeing it. Here are a few thoughts based on list of steps: This is a terrible idea. There is no reason to update rows of the entire table to inactive, only at some later point to set them back to active. Don't change rows you don't need to change. This is really unclear. What is the format of the "import" array? Are there ID's? I don't see how you could classify anyone as a "Left user". If they were not found, then they should be added as a new user. Thus all users are either found (existing) or not found (new). It seems like there are a number of baked in assumptions here that aren't clear, starting with where this import file comes from. What constitutes "active" state in this system? What exactly is the format of the import file?
  5. And everything I wrote previously still applies. let json_array = {} json_array.excludes = [] // Use array method json_array.excludes.push("a") json_array.excludes.push("b") //array syntax json_array["excludes"].push("c") console.log(json_array) I Updated the codepen as well with this example code.
  6. Personally, I would recommend uninstalling xamp and using docker. There are a lot of projects out there that offer a docker-compose that orchestrates a lamp environment for you. Devilbox is a massively complete project that offers a myriad of different configurations (not just lamp), but there are many others, not to mention lots of tutorials showing how you can create your own. I even made a project myself to support some of the work I do. I have seen a good deal of discussion of people who primarily make Laravel apps using Laravel Sail, but it can be used for any php project afaik. With that said, if you absolutely must have something similar to what xampp provides, people seem to like Laragon.
  7. the push method is for an array. Adding to objects can be done in a few ways: Using array syntax: obj['property'] Using "." notation: obj.property obj = { 'foo': ['apple', 'banana'], 'getFoo': function() { return this.foo } } console.log(obj.getFoo()) obj['bar'] = ['red', 'green'] obj.foobar = function() { return this.foo.concat(this.bar) } console.log(obj.bar) console.log(obj.foobar()) Example code in this codepen.
  8. In the documentation about external fonts, it specifically provides an example using google fonts. Try adding this to your initialization of dompdf: $tmp = sys_get_temp_dir(); $dompdf = new Dompdf([ 'logOutputFile' => '', // authorize DomPdf to download fonts and other Internet assets 'isRemoteEnabled' => true, 'isFontSubsettingEnabled' => true, 'defaultMediaType' => 'all', // all directories must exist and not end with / 'fontDir' => $tmp, 'fontCache' => $tmp, 'tempDir' => $tmp, 'chroot' => $tmp, ]); $dompdf->setPaper("A4", "portrait"); $dompdf->loadHtml($_template, "UTF-8"); $dompdf->render(); $dompdf->stream(time() . ".pdf", array("Attachment" => false));
  9. Yes recently (v7) PHP was changed so that you can have a private constructor in a class meant to be used statically, so that it is impossible to instantiate an object of that class externally using the 'new' keyword. This is not related to object cloning. Object cloning requires the 'clone' keyword. <?php $obj1 = new stdClass(); $obj1->foo = 'Object1'; $obj2 = $obj1; // $obj1 and $obj2 point to same object. They "reference" the same object echo $obj1->foo . PHP_EOL; // Changing $obj2 changes the underlying object pointed to by both variables $obj2->foo = 'Object2'; // Changed the property of $obj2, and thus This prints 'Object2' echo $obj1->foo . PHP_EOL; // This time we use clone // Object 3 is an independent object, only the properties were copied $obj3 = clone $obj1; // Changing $obj3 does not change $obj1/$obj2 $obj3->foo = 'Object3'; echo $obj1->foo . PHP_EOL; // Still prints 'Object2' echo $obj3->foo . PHP_EOL; // Prints object3 Looking at a private constructor example, does this affect the use of new? Yes. You can't instantiate it with new, only using a static method. <?php class Test { private ?string $name; private ?string $guid; private function __construct(?string $name = null) { $this->name = $name; $this->guid = uniqid('', true); } public static function makeTest(?string $name = null) { return new static($name); } public function getName() { return $this->name; } public function getGuid() { return $this->guid; } } $foo = new Test(); This triggers a runtime error: Fatal error: Uncaught Error: Call to private Test::__construct() However, using makeTest() to create an object, does this somehow prevent variable assignment or clone behavior? Not at all! class Test { private ?string $name; private ?string $guid; private function __construct(?string $name = null) { $this->name = $name; $this->guid = uniqid('', true); } public static function makeTest(?string $name = null) { return new static($name); } public function getName() { return $this->name; } public function getGuid() { return $this->guid; } } $obj1 = Test::makeTest(); echo "Name:" . $obj1->getName() . PHP_EOL; echo "Guid:" . $obj1->getGuid() . PHP_EOL; $obj2 = Test::makeTest('Object2'); echo "Name:" . $obj2->getName() . PHP_EOL; echo "Guid:" . $obj2->getGuid() . PHP_EOL; $obj3 = $obj2; echo "Name:" . $obj3->getName() . PHP_EOL; echo "Guid:" . $obj3->getGuid() . PHP_EOL; $obj4 = clone $obj2; echo "Name:" . $obj4->getName() . PHP_EOL; echo "Guid:" . $obj4->getGuid() . PHP_EOL; You will see something similar to this: Name: Guid:6372930b031f27.11028500 Name:Object2 Guid:6372930b032385.75458089 Name:Object2 Guid:6372930b032385.75458089 Name:Object2 Guid:6372930b032385.75458089
  10. I have a bit over 14k rep at SO with 99.9% of that from answering questions. I've all but given up on going there, as they have made the site, despite protestations to the opposite, miserable for new or inexperienced developers and for anyone trying to help them, especially in the #php tag. There are a few overzealous mods who have made it their mission to criticise or close questions from novices, even going so far as to attack people answering these questions. It's gotten to the point that there is really no point in answering anymore questions, because the questions get closed or pointed to existing answers even when there is a substantive details that make the pre-existing question irrelevant. SO's been going in this direction for quite a while, but to read that someone would be threatened with expulsion from SO for asking too many questions, is mind boggling.
  11. Hopefully you learned a couple of important principles throughout this exercise: html id's should always be unique in a page. For this reason they are rarely used for styling, again unless the styles being bound to them are also unique to that element in general classes are much better for styling groups of things, and as Barand showed, for attaching a related event listener.
  12. Thanks for reporting this! Thanks for fixing @requinix
  13. I want to throw in my 2 cents here: Why use an abstract class? You have a number of concrete classes that will inherit attributes and behavior from this common ancestor. The ancestor itself is not specific enough to be an actual thing. In your case you should decide -- is Product "abstract" for your use? It doesn't seem to be, but by no means should you have a concrete class named Products! If you want to use plurals, great, but most often people will use singular naming. It seems that you did this Product vs Products thing just to get around the naming issue, which should tell you that you are on the wrong track here. In Products, your constructor just sets a lot of of attributes, all of which could easily be part of the Abstract Product class. Move that into the Abstract class. One obvious thing missing is the idea of what "type" of Product an individual Item is. Your specific getFur, getDVD etc, are just completely off base and shouldn't exist. The database should have a type or item_type column in it that describes the type of item. This would typically be constrained by a table which has a row for each possible item type, used as a foreign key for your products or items table. What's an alternative approach here? MVC would tell you that you could use a "Model" class. Generically a model class knows how to map data from a database table into attributes. We know from your code that table is named "skandi" So taking a step back, how about thinking about what you might need to facilitate the data from a table. What might you have generically? <?php abstract class TableModel { private $databaseConnection; protected $database; protected $table; protected $primaryKeys = []; protected $attributes = []; private $data = []; protected function getDatabase() { return $this->database; } protected function getTable() { return $this->table; } protected function getPrimaryKeys() { return $this->primaryKeys; } protected function setAttributes(array $attributes) { $this->attributes = $attributes; } public function getAttributes() { return array_merge($this->primaryKeys, $this->attributes); } public function setDatabaseConnection($databaseConnection) { $this->databaseConnection = $databaseConnection; } protected function getDatabaseConnection() { if (!$this->databaseConnection) { throw new \Exception('Database Connection Uninitialized'); } return $this->getDatabaseConnection; } protected function getFullTableName() { return '`' . $this->getDatabase() . '.' . $this->getTable() . '`'; } public function getAllRowsSQL() { // Just an example to show the possibilities. return 'SELECT * FROM ' . $this->getFullTableName(); } } class Product extends TableModel { protected $database = 'yourDb'; protected $table = 'skandi'; protected $primaryKeys = ['id']; protected $attributes = ['sku', 'name']; } $product = new Product(); $conn = 'SomeDbConnection'; $product->setDatabaseConnection($conn); echo $product->getAllRowsSQL() . PHP_EOL; echo implode(',', $product->getAttributes()) . PHP_EOL; You most likely wouldn't have a getAllRowsSQL method, but I provided it just to give you an idea of where you might go with this. Since TableModel is generic for any type of table, you can concentrate on how to generically query data from any table and load it into the $data attribute. You could also consider things like insert/update and delete. All the other attributes you have which are specific to the skandi table, might lead you in the direction of an Interface or possibly an interface with a set of common "Product" traits. I only mention this because you seem to be on the path of needing to explore those features. In general, interfaces allow for passing a de-coupled object into a class as a parameter. Rather than have the specific insert/update/delete routines in a TableModel, you might instead want your abstract TableModel class to implement an interface that a separate database management class might want to call instead. getFullTableName() is an example of a method that might be helpful in a database management class, where you would pass a Product object into and have it do the specific SQL calls, using things like the table name, keys and attributes.
  14. I would again just have a command line job that selects 1-N random users from the user base, and will access their feed programmatically, using the basic method I outlined in my prior reply. If you wanted to up the level of sophistication, you might make this asynchronous using something like https://github.com/spatie/async to provide a more realistic simulation, as your artificial users can each be running through the read/like/reply processing simultaneously. This type of simulation can create the type of race conditions that might happen in reality but won't appear during normal unit or regression testing.
  15. It's fine to add code in a thread. That's not really double posting the way we look at it. The main problem that happens is when people change their code over the course of a thread, and don't post the current version, leading to lots of confusion. We would rather have people repost code so it's clear to everyone what the current code looks like. Don't do this: $query = 'SELECT COUNT(*) FROM ' . $this->table . ' WHERE sku = "$this->sku"'; You have introduced a possible SQL injection. Bind all parameters whether that be from insert/update/delete (DML) or select. Alternatively to doing this, what mac suggested is that you wrap your insert in a try/catch. If you have a relevant constraint on sku (primary key or unique index) on that attribute the database itself will disallow the query with a constraint violation. You then handle the database exception. There's a couple arguments for that approach: You don't add a SELECT every time since it really is an exception You will need to have made sure that your database has the proper constraints so that duplication sku's can't happen which is more robust Furthermore it is handled in mysql via a unique index, which means that any queries you do that might need to search by sku will be covered by that same index There are other errors that can occur and your code will catch those and send back an appropriate error, rather than possibly leaving your UI in an incomplete state because of a runtime error within the ajax script
  16. ginerjm is exactly right. CSV format is simple. If you have a string you need to delimit it with double quotes. In other words, you need double quotes around any string field. It is generally safe to put double quotes around all your fields, although this might affect the way the particular spreadsheet handles the data if it is numeric That introduces the possibility that there could be those same quotes within the string, so you need to first take the step of "escaping" any of those quotes. Each field needs to be separated with a comma Each line needs to end with a carriage return/line feed combination. Now you can certainly write this code yourself, but the modern way would be to use a library that already handles these details for you, and reduces your requirements to using the library and letting the library do the work for you. If it's a decent library it has unit tests and you are leveraging not only the work other people put into the library, but also the testing they did to give you confidence their code works correctly and to the csv spec. Here is one such library that is easy to use: https://github.com/thephpleague/csv What will help you here is to load the data into an array and use that to output your html table rather than doing that will fetching each row. Put that code into a function which you keep in an included script (including the query code). The csv output can then rely on using this same query code to re-run the query. Your "csv script" will: use the same function to execute the query and load the array It will then set the http header as needed to return the data with the mimetype for csv, and optionally to force the browser to download it as a file You do this setting the http header to Content-Disposition: attachment; filename="somefile.csv" Use your routines or a csv library to convert the array to csv format return that data
  17. We have to see at very least the parts of your code you know or suspect don't work. Use the code button <> to paste those parts of code into your messages.
  18. You excluded a possibility initially, which is that you can select a random group of users from the existing population to be followers, rather than "assigning x". So a new user could start out with 0 followers, or "all followers". What you didn't describe is the process by which new users are created. So I would probably have a number of command line process jobs. Create new user job (includes initialization of following) Add new post job Read feed randomly like within reasonable threshold randomly unfollow within reasonable threshold (probably want this to be relatively low) randomly reply
  19. In my opinion, you want to build a "responsive" site, where you have certain thresholds you use for mobile devices. Rather than start with the idea that you have a max, allow the site to grow and shrink based on the device specific (viewport) attributes like vh and vw, as well as using the flexbox properties that allow for growth and shrinkage. So for example let's say that you have a fixed height for a header, and below that you have a flexbox that should fill available vertical height and width. You might have a style like this: .app { font-size: 15px; color: #fff; height: 100vh; width: 100vw; } .header { background-image: linear-gradient(to right, #18a0BE, #622db9); height: 55px; display: flex; } .app__container { height: calc(100vh - 55px); display: flex; } .main { background-color: #edf1f3; flex: 1; } And your markup might be something like: <body class="app"> <header class="header "> </header> <div class="app__container"> <main class="main"> <div class="cards"> </div> </main> </div> </body>
  20. Flexbox and/or grid should handle everything you want. I would start with using flexbox for all of the layout pieces you have already described, so certainly you want a container div for those so that you can use display: flex. At that point it's just a matter of applying the appropriate parent/container properties or child div properties you desire. This article might help if you need a refresher: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
  21. Having looked at the code further, you don't want to use the esc_html___ function, or at least not on the url. That function is changing the anchor tag markup so that it no longer will function as a url. Try this instead: <?php /* translators: %s Order date */ printf( esc_html__('Tracking number', 'woocommerce') . ':<a href="https://www.fedex.com/fedextrack/?trknbr=%2$s">%2$s</a>', esc_html($shipping_carrier), esc_html($ups_trackingno) ); ?> I don't know if your site is multilingual, but the primary purpose of esc_html__() is to do translation, but it also "escapes" any html as I mentioned. Obviously there is no reason to translate the url, but you might need translation of the text string "Tracking number" (or not).
  22. If the script doesn't parse, that could be a reason you are not seeing errors. Since most editors catch these types of problems in advance, I'm not sure why you would not fix them in advance. You can also use the command line linter with php -l sourcefile.php. Sometimes this trick can help get around the problem of a stubborn parsing error that causes a 500 error: Make a script named something like debug.php: <?php //debug.php error_reporting(E_ALL); ini_set("display_errors", 1); require("filewitherrors.php");
  23. We can't guess what your code looks like. It might help to explain what you are using one of these characters for.
  24. So it looks like you are using your own tokens for login. That is not a good idea. You should be relying on the session instead. If you expect to have a cluster of app servers, you might need to change session storage so that it uses your database, or redis/memcached instead of files, or you can use a load balancer that supports the configuration of a "sticky" session, but otherwise, you don't want to be creating and managing your own session/authentication token for anything other than the remember me feature. Sessions already, when properly configured, utilize a cookie. You also want to make liberal use of session_regenerate_id. From what you posted, this has DRY/ logic issues: if (isset($_POST['remember-me'])){ $_SESSION["loggedin"] = true; $_SESSION["username"] = $username; $_SESSION['the_usr_id'] = $user['user_id']; echo "<hr>"; echo setRememberMeToken($pdo, $user['user_id']); echo "<hr>"; header("location: dashboard.php"); } if (!isset($_POST['remember-me'])) { $_SESSION["loggedin"] = true; $_SESSION["username"] = $username; $_SESSION['the_usr_id'] = $user['user_id']; echo "<hr>"; echo "<hr>"; header("location: dashboard.php"); } Again, I don't have your code, but you have a repetition of code, and worse yet that code is actually not relevant to the variable you are checking (!isset($_POST['remember-me']). What you want to do is avoid blocks like this, which are also mutually exclusive. So again, assuming that this is part of a block where you already established successfull login previously, you can rewrite your code like this, to separate the remember-me check so that it only does what is relevant to the existence of that flag. I will also point out that if the user logs in without the remember me checkbox, you should remove the remember me token, but your code doesn't do that. Something like this would be better, and also fix your current hole. // Assumes authentication succeeded above this code $_SESSION["loggedin"] = true; $_SESSION["username"] = $username; $_SESSION['the_usr_id'] = $user['user_id']; // Not sure why you need this? if (isset($_POST['remember-me'])) { setRememberMeToken($pdo, $user['user_id']); } else if (!$_SESSION['rememberMeLogin']) { // Was not a "remember me" authentication AND remember me was unchecked. So should remove the remember me token & Delete the cookie. unsetRememberMeToken($pdo, $user['user_id']); } header("location: dashboard.php"); exit; Another thing I would suggest is not to use md5, but used sha1 instead. md5 has a smaller collision space. I would also add something to the random input to the hash (md5,sha1). So perhaps add something like username + random bytes. People can generate a large table from random byte input (a rainbow table) and look for matches. By doing so they might figure out you are just using random byte combinations of a certain size. It's not a major security hole, but one you can protect against by not just hashing random characters of the exact same size from a routine. This is similar to the idea of using a "salt".
  25. One other thing I would say about remember me, is that a good additional security feature is to set a session variable boolean like "usedRememberMe". Any time a user escalates privilege (ie. they want to change something in their profile like an email address, or create an order, or become a system moderator or superuser) you want to prompt for re-authentication and generate a new session id. You can use the "usedRememberMe" session variable as a factor in what you might do in this circumstance. For example, you might choose to require re-authentication more aggressively if they logged in via the remember me cookie. It can be helpful to keep track in the session how the user was authenticated.
×
×
  • 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.