Jump to content

gizmola

Administrators
  • Posts

    5,878
  • Joined

  • Last visited

  • Days Won

    139

Everything posted by gizmola

  1. 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));
  2. 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
  3. 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.
  4. 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.
  5. Thanks for reporting this! Thanks for fixing @requinix
  6. 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.
  7. 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.
  8. 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
  9. 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
  10. 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.
  11. 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
  12. 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>
  13. 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/
  14. 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).
  15. 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");
  16. We can't guess what your code looks like. It might help to explain what you are using one of these characters for.
  17. 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".
  18. 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.
  19. Starting with a basic fact: Cookies are owned by the user. Heed Mac's advice on this. A remember me cookie is a standin for a user having presented their name/password for authentication. You have implemented Mac's idea for the most part, which is standard The only time you need evaluate the remember me cookie is if you have an unauthenticated user. Rather than prompting for a login, you can use the remember me cookie to validate they are who they say they are, via the remember me cookie. So that cookie requires both username and the hash value. You need the expire date for this, because again, you can not trust the cookie. A user could just go in and set the expiration date so the cookie never expires. You can also use the cookie expiration as an added check if you want. This would further verify the user has not tampered or constructed a remember me cookie to bypass login. For all these reasons, sessions do not matter. If user is unauthenticated Do they have a remember me cookie? Check the database for the remember me value and check that the value has not expired If this criteria is matched, log the user in This should involve the exact same loading of session data as if the user had logged in with username/password. Otherwise redirect to login page
  20. 2 things that will be of value for you: PHP has include/require. It allows you to put something in a script and include it as if you had typed it in. What jumps out immediately is that you have database credentials. When you change them you don't want to have to change every script in your system. Put them in a script and require_once them instead. Here is a pretty typical PHP application directory structure you can use. Your webserver document root should be set to the /path/to/your_project/public directory. This allows you to keep some files outside of the webroot, so hackers can not attempt to execute them directly your_project/ ├─ include/ │ ├─ config.php │ ├─ utility_functions.php ├─ public/ │ ├─ css/ │ ├─ js/ │ ├─ index.php In the /your_project/include/config.php file you put your database setting variables. $DATABASE_HOST = 'localhost'; $DATABASE_USER = 'root'; $DATABASE_PASS = ''; $DATABASE_NAME = ''; mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); $con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME); if (mysqli_connect_errno()) { // If there is an error with the connection, stop the script and display the error.// exit('Failed to connect to MySQL: ' . mysqli_connect_error()); } When a script needs a mysqli connection to use you require_once config.php. In index.php for example: <?php // index.php require_once('../include/config.php'); // Rest of code here, can already use $con The other thing I would suggest is trying to use functions for individual tasks. If you can put code into a function, it will be possible to re-use it in multiple scripts. By changing to a typical structure like the one I describe, you also open yourself up to the possibility of using component libraries in your application, as well as autoloading via the composer dependency management tool. This does require some basic understanding of PHP's object oriented programming syntax, at least so far as being able to instantiate an object with "new className()". This is probably the best thing as a novice developer you could do at this point, other than to port your application to a basic framework like Cakephp. Seeing the road you are going down, and in recognition of your neophyte status, I would highly advise taking a look at using Cake, because it is very simple and easy to understand, and will give you the basic MVC structure a web application should have. It's easy to see for most of us, that you are already making huge mistakes, and writing spaghetti that will be buggy, insecure, impossible to maintain, and involving tremendous reinvention of the wheel. CakePHP can relieve you of a lot of that, and has a simplicity to it that is well suited for relative beginners. I tried to find you a free online course to help you learn CakePHP, and this one looked decent, and the person teaching how to use it is well spoken and knowledgable. If you do use CakePHP I think the equivalent for the public directory/webroot is a directory named /webroot. Frameworks like CakePHP have code generation tools and will typically offer a way to initialize your project via composer. This is covered, I believe in the tutorial series I posted about. Here is the main CakePHP site: https://cakephp.org/ Basically what you will do is make a new CakePHP project on your workstation. You can then "port" ie. move relevant code you want to preserve into files in your CakePHP project. CakePHP gives you structure you don't have now, like controllers/routing, models (that will match your database tables) and views (templates). Once you get these simple concepts, the framework will save you incredible amounts of time, in providing you built in classes and structure that let you concentrate on your actual logic and functionality.
  21. Another thing you have not thought through is what happens when you have 2 files with the same name. What you have is a naive strategy, that as, kicken pointed out, can open you up to a variety of exploits. This is what most people do: In your "media" table have a column for the path to the stored file Generate an internal name for the file. MD5, SHA1 etc are good places to start Provide a variety of input to the hash example: $internalName = sha1($orignalName . uniqid('something', true) . date(DATE_RFC2822) . $userid); Make this the name of the file you store + mimetype extension have a column for the original file name Run hygiene functions on this name, that does things like: remove any non-characters remove any path characters remove html remove spaces and replace with underscores or dashes Exploiters will try things like names that included multiple extensions, and can in some cases fool your webserver into running code examples: foo.jpg.php, foo.bar.cgi.jpeg remove any periods other than the one at the end of the file name (.ext) and either replace those with underscore or dash, or remove. have a column for the mime type of the media Run function(s) on the file that determine if the mime type of the file matches what you will allow Check that the extension of the filename matches the mimetype When it comes time to display a link to the document, you will use your internal hash id to find the document. Depending on what you are doing with the media you can use html markup like the alt attribute to display the "original" name, and/or for download purposes, you can specify that in the content-disposition header like so: Content-Disposition: attachment; filename="filename.jpg" So your download script might have something like this in it: <?php $fileId = $_GET['fid']; // Db code looks up file in media table, returns $media row header('Content-type: ' . $media['mimetype']); header('Content-Disposition: attachment; filename="'. $media['original_name'] . '"'); // open file and return data
  22. Please use the <> for adding code snippets in the future. I edited your original post. Remove the echo. You are already calling multiple functions, which take parameters. Parameters can not include php blocks or statements. As it is, the printf function is returning output. If you look at the php manual for printf you should be able to see why it is being used here. It takes parameters and injects them into the string using the parameters being passed to it. <?php /* translators: %s Order date */ printf( esc_html__('Tracking number : <a href=\\"https://www.fedex.com/fedextrack/?trknbr=%2$s\\">%2$s</a>"','woocommerce'), esc_html($shipping_carrier), esc_html($ups_trackingno) ); ?> I reformatted the block so you can more easily see the functions and parameters being passed.
  23. Websafe colors is an artifact of the days when memory constrained graphic cards only had support for single byte ( 256 colors) per pixel. Those days are long gone, and you should not be concerned with the 216 websafe colors unless you are going for some sort of retro color palette.
  24. For a chrome extension I'm pretty sure you have to assign permissions in your manifest file, if you want a specific host to have access. Then use chrome.cookies api. See: https://developer.chrome.com/docs/extensions/reference/cookies/ I'm not sure what you are trying to do with cookies in your extension, but an alternative that isn't chrome specific would be to use local storage. Again you need to specify in the manifest: https://developer.chrome.com/docs/extensions/reference/storage/
  25. Maxxd and ginerjm pretty much nailed it. The warning was introduced in PHP version 7.2. Is it possible you can get an updated version of the template you are using? You might need to make a lot of these types of patches. I'd probably make this variation on ginerjm's fix: $subcategories = empty($subcategories) ? array() : $subcategories;
×
×
  • 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.