Jump to content

kicken

Gurus
  • Posts

    4,704
  • Joined

  • Last visited

  • Days Won

    179

Everything posted by kicken

  1. Just remember that the stuff you find in .htaccess files are just Apache configuration directives. So when you're unsure of something the thing to do is to visit the Apache directive index and find the directive in there to find the full documentation on it. Most of the time, this will give you the information you need. For example: From the RewriteCond documentation So the %{ means it's a server variable, as opposed to some other variable types. The syntax of conditions is covered in the same RewriteCond documentation. !=80 for example is covered by So it means (Not)(Equals 80) As for what condition to write, this mostly just requires you to use your brain. What condition you use depends on what you're testing against. If you're testing against %{SERVER_PORT} then the value will be a number so you'd check for =80 or =443 for example. It wouldn't make sense to check for the string 'https' in that case. Likewise the parts that require regular expressions require you to use your brain to come up with the correct expression. If you don't know regular expressions very well or at all, then you'll need to spend time learning that. Regular expressions are not just an Apache thing so their manual doesn't really cover them in detail. It does at least give you the basics and what you need to know to look for further help: The term "Regular expression"; Links to documentation and additional help. All in all, Apache has pretty good documentation. If you're struggling with it, you'll be in for a world of hurt when it comes time to deal with things that have much less well-defined documentation.
  2. The best thing to do in my opinion is to just have a way to switch the active user of your session, and expose this functionality to administrators only. For example in my systems when an administrator looks up a user in the user listing there is a link called 'Impersonate' available to them. When clicked, this modifies the $_SESSION['UserId'] (where I happen to store my login info) value to that of the selected user and as a result the person is now "logged in" as that user. I also store the ID of the administrator in a separate session variable so when they "log out" it just returns them to their session rather than actually logging them out of the system. With this method there's no need to know your users password. There's no master password that could accidentally leak. You can control better who can use this functionally via permissions (we only let a small group of 'Super Administrators' do this).
  3. See how you have data-id='".$r['id']."' for your $r['id'] variable? Do the same thing with your direction variable. data-direction='".$r['direction']."' Then in your javascript code you can access these values via the dataset property on the element. onclick="newTransactionLine(this.dataset.id, this.dataset.direction)"
  4. Why can't your "High security" pages be just like your "Low security" pages, but with the extra checks? Doesn't make sense to me why you have to send them through some post request to the index page first.
  5. I prefer using pdf-puppeteer for this job. It requires NodeJS but otherwise is fairly easy to setup. I uses a headless chrome instance to render the HTML into PDF so it supports fairly modern CSS (but not necessarily bleeding-edge). Render your template out to a temp file then pass that to the script to generate the PDF. Use a short JS script like this to handle the PDF generation const fs = require('fs'); const pdf = require('pdf-puppeteer'); const args = process.argv.slice(2); if (args.length < 2){ console.log('Usage: html2pdf source destination [options]'); process.exit(20); } const source = args[0]; const options = args.length === 2?JSON.parse(args[1]):{}; fs.readFile(source, 'UTF-8', function fileReadSuccess(err, data){ if (err){ throw err; } pdf(data, callback, options); function callback(pdfData){ console.log('PDF Data length: ' + pdfData.length); } }); Kick off the process with PHP using exec(). $cmd = $this->createCommandLine($source, $destinationPdf); exec($cmd, $output, $ret); if ($ret !== 0){ throw new \RuntimeException('Failed to generate PDF with command [' . $cmd . ']'); } $pdf = file_get_contents($destinationPdf);
  6. Then you need to check a few things. Use the third parameter to get the exit-code and see what it is. Typically 0 would mean success, anything else would be an error. There are two ways a program can output text, either via STDOUT, or STDERR. By default only STDOUT is captured. To capture STDERR as well you need to redirect it to STDOUT. This is done by adding 2>&1 to the end of your command. It's generally best to use a full path to the executable as your script may be running with a different $PATH value than you're normal shell.
  7. It doesn't appear to be used. It might just be there for consistency sake with the sw_id array. If both array's are auto-generated somewhere than it might have just been easier to keep two lists of pairs and dump them to an array rather than one list of pairs and one list of values only. I would have just written this to use either a 2d array or array of objects rather than this flattened array approach. It's unnecessarily hard to understand as written.
  8. If you look at the manual page for exec you'll see that it returns just If you look at the arguments list, you'll see there are two additional arguments you can pass to exec So if you want the full output, you need to pass a variable as the second argument and it will be filled with the output. exec('swetest -h', $output); var_dump($output);
  9. Maybe you should show what kind of redirect chain you're getting, then you can figure out where your configuration is wrong, or at least why there are multiple. Like I said above, there shouldn't be more than one, maybe two in the case of a directory.
  10. Alternatively, configure your web server to show a particular page on error. For apache you might do for example ErrorDocument 500 /500.html Exact configuration will depend on your server version and setup.
  11. I wouldn't be overly worried about multiple redirects, but there shouldn't be any regardless if you do things correctly. The example I showed above covers the HTTP version of URLs entirely, www or no www. Either version it will redirect to the correct HTTPS version of the url (no www in my case). So that leaves only the www vs no www scenario on HTTPS to worry about and that you'd use mod_rewrite for. In my case, that's #Force no-www RewriteCond %{HTTP_HOST} ^www.aoeex.com(:\d+)?$ RewriteRule ^/?(.*) http://aoeex.com%1/$1 [QSA,R=301,L] So in every scenario there would only be one redirect. http://www. -> vhost Redirect sends you to the right URL. http:// -> vhost Redirect sends you to the right URL https://www. -> mod_rewrite sends you to the right URL https:// -> no redirect necessary. If you're getting more than one redirect you're probably configuring something wrong. At worst you might get two if DirectorySlash is on (is by default) and you request a directory without the trailing slash. edit: There are non-mod_rewrite ways to handle the www/no-www scenario too.
  12. It tells you exactly what to do on that page you linked. For a simple http to https redirect, just create a http vhost with a simple Redirect statement. For example, from my site's configuration: <VirtualHost *:80> ServerName aoeex.com ServerAlias www.aoeex.com Redirect permanent / https://aoeex.com/ </VirtualHost>
  13. It's fine. Though you ideally shouldn't have a bunch of spaces everywhere like you do. Just put a space between attributes, not around the =. Using <input type="button"> creates a simple button that effectively does nothing. It will NOT submit your form. This type of button is mostly used in combination with javascript. Using <input type="submit"> creates a simple button that will submit the form and is a standard practice for submitting forms. Using <input type="reset"> creates a simple button that just resets the form's fields to their default values, it does NOT submit the form. Using <button> allows you to create nicer button because it allows more than just text. For example, you can combine text and an image. <button type="submit"> <img src="/images/search.png" alt=""> Search </button> With <button> you also have type="button", type="submit", and type="reset" which have the same semantics as on <input>. It doesn't really matter, though I personally find double-quotes on attribute values to be more correct and causes fewer issues. Use which ever one you want, but be consistent and use the same one everywhere. This is an artifact of the days when XHTML was popular and the thing to use. It's called a self-closing tag and is necessary in XHTML as everything must have an open and close tag to be XML compatible. These days it's best to stick to plain HTML which does not use XHTML specific things like self-closing tags. First of all, it is <label for="">, there's no underscore in there anywhere. Second, no you do not provide labels for each option in a select. The label is to describe the input as a whole, your options are labeled by their text content. They are both correct. It's mostly a matter of preference, or sometimes dictated by your layout. <label> can be be associated with an input either with the for attribute, or by having the input enclosed within it. Enclosing the input is convenient, but it may not always be possible when considering layout requirements.
  14. The page displays thin rounded borders for me in chrome and firefox. Make sure your not having cache issues.
  15. Apply your styles to the <input> tag rather than a <span> tag.
  16. So someone can't order something to be picked up tomorrow? I do that somewhat frequently with lowes/home depot. In any case, you'd essentially just create a script to change that field. <?php $online = intval($argv[1]); $db = new PDO('mysql:host=localhost;dbname=store', 'username', 'password'); $statement = $db->prepare('UPDATE table SET online=? WHERE whatever'); $statement->execute([$online]); Then setup two cron jobs to run that script at whatever time you want to toggle the field and it's desired value # Set online=1 at 9am 0 9 * * * /usr/bin/php /home/you/toggleOnline.php 1 # Set online=0 at 5pm 0 17 * * * /usr/bin/php /home/you/toggleOnline.php 0 You'll have to get more sophisticated if you want to handle things like weekends, holidays, etc.
  17. Have a look into GROUP BY and GROUP_CONCAT
  18. It's the addValue function call that ate up the time. Keeping the object but making the values property public and just doing $columns[$idx]->values[]=$value; resulted in the same 1.5 seconds run time. I'd probably go with option 3. It keeps the data and the formatting de-coupled and seems to be more correct placement of the output function to me. Any of them would be fine really though.
  19. If the overall function of the loops doesn't change between versions then it generally doesn't matter which way you do it foreach (1000){ foreach (3){ something; }} and foreach (3){ foreach (1000){ something; }} are both 3000 executions of something; and it's ultimately the time of the something block that determines the time spent. Sometimes the order of the loops can help make whatever something; is more efficient by say reducing the number of variable assignments/lookups etc. Other times it truly doesn't make a difference so you'd just do whichever seems easiest to understand. I'd probably start with something like this to transform the data and see how it goes. $data = json_decode($yourJsonString); $columns = array_map(function($v){ return new ColumnData($v); }, $data->columns); foreach ($data->values as $row){ foreach ($row as $idx=>$value){ $columns[$idx]->addValue($value); } } That makes the main loop simple and just shifts the data around basically into a more usable format. The ColumnData class is just a simple container to hold the data temporarily. I tested the above on a 54MB file of random data and it took about 8 seconds and used ~575MB of memory (439MB for the json_decode, 136MB for the sorting). class ColumnData { private $name; private $values; public function __construct($name){ $this->name = $name; $this->values =[]; } public function getName(){ return $this->name; } public function getValues(){ return $this->values; } public function addValue($value){ $this->values[] = $value; } } The ColumnData class could be removed and simple array's used instead, not sure how that'd affect runtime/memory usage. Edit: Tried this, reduced the runtime from 8 seconds to 1.5 seconds, but had no effect on memory usage. Once you've got the data all grouped by column, just generate the classes you need from there. //This assumes time is the first column. $timeColumn = new TimeValues(array_shift($columns)->getValues()); $series = array_map(function($v){ list($fn, $point) = explode('_', $v->getName()); return new Series(new Point($point), new Aggregator($fn), new DataValues($v->getValues())); }, $columns); $collection = new SeriesCollection($timeColumn, ...$series);
  20. Not sure I understand your desired output. Do you want to take each value item and transform them such as ["2020-06-13T14:02:02Z", 4.3527550826446255, 5.668302919254657, 0.6175362252066116] //becomes three objects new p51("2020-06-13T14:02:02Z", 4.3527550826446255), new p55("2020-06-13T14:02:02Z", 5.668302919254657), new p56("2020-06-13T14:02:02Z", 0.6175362252066116)
  21. I have no idea still what you're trying to do, but it sounds like you just don't want to use COUNT() at all. Just select id, owner and then loop over the returned rows in your code. Count will tell you how many rows match your query, but you cannot select it along with other columns and get meaningful results unless you use GROUP BY to divide the results into different sets. Then COUNT() will tell you how many rows exist in each of those sets.
  22. Any columns that you are selecting but not COUNT()'ing need to be part of a GROUP BY clause. SELECT COUNT(id) c, id, owner FROM cities WHERE owner IN ('21', '37') AND available = 0 GROUP BY id, owner
  23. You can't loop over the column result-set multiple times. That code will work for the first data row, but then return false for every other data row because you've already reached the end of the column result set. You should fetch that column data into an array before hand then loop over that array. function getLuTableBody($lu_tableName) { $tableColumns=getTableColumns($lu_tableName); $columns = []; while ($columnData = $tableColumns->fetch_assoc()){ $columns[] = $columnData['COLUMN_NAME']; } //Might as well check for 0 columns and bail early. if (!$columns){ echo "problem with column data"; return; } $tableBodyHtml =""; $tableData=getTableData($lu_tableName); if ($tableData->num_rows > 0) { while($row = $tableData->fetch_assoc()) { foreach ($columns as $columnName){ $tableBodyHtml .= "<td>$row[$columnName]</td>"; } } } else { echo "problem with record data"; } return $tableBodyHtml; } You're also missing your <tr> </tr> tags for each row, and you shouldn't be echo'ing stuff if you find a problem. Throw an exception or return false or something.
  24. With composer you should be keeping your composer.lock file in your version control. If you upgrade and things don't work out then just revert your composer.lock and composer.json files, delete the entire vendor directory and run composer install and it will re-install whatever versions you previously had specified in the lock file. Googling your foreign key error seems to indicate a likely cause is column type mis-match. Maybe one of those updates changed the type of a column from int to bigint or similar. You'll need to check your different constraints to verify they match.
  25. His explanation of regular expressions and the first argument of RewriteRule is pretty poor IMO, but you did miss one part of it at 12:20.
×
×
  • 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.