Jump to content

kicken

Gurus
  • Posts

    4,704
  • Joined

  • Last visited

  • Days Won

    179

Everything posted by kicken

  1. The binary log / mysqlbinlog is just one way to hook into mysql and get notified of changes at a low-level. You can certainly build your own system if you want.
  2. Regarding detecting changes, a hash would be able to tell you something changed but without an indication of which side is newer. A time stamp could tell you which side is newer but relies on accurate in-sync time keeping at both ends. A counter would work for simple one-way replication. If the slaves only ever need to download new data from the master and never upload changes then I'd just go with a counter. Have the master update a counter with each operation then each time a slave is sync'd it'd store the current counter value. On the next sync ask the master for changes made since the counter was at X value (or just do a full sync). For a Mysql master this could probably (just guessing here) be done relatively easily using binary logging and the mysqlbinlog tool as suggested by Jacques1 in a previous thread. If you need bi-directional syncing then things would become more complicated.
  3. Sure, just define the variables in the if/else if/else branch accordingly. if (...){ $a = 1; } else if (...){ $a = 2; } else { $a = 3; } echo $a; The value of $a will change according to how the program flows based on whatever conditions you put in for the ... parts. I tried following your code to make suggestions on a better way, but honestly the code just does not make much sense to me at all. First of all, I am guessing this is not at all what you wanted: if(!$currentWeekNumber<$a AND $EngReleaseDate == NULL){ The ! will convert $currentWeek to a boolean value then compare that to $a, so you get essentially 0 < $a since any valid $currentWeek value would be negated to false / 0. Since $a should only be 1 - 53 then that condition would always be true meaning that branch depends only on the value of $EngReleaseDate. Second, your $a, $c, and $d variables are + 9, + 10, and +11 ahead of $SubmittalPromiseWeek. Your $b, $e, and $f are +3, +4, and +5 weeks ahead of $currentWeekNumber. So the data you're storing doesn't seem to line up with your 8-weeks out goal. Lastly you can probably have the database do a lot of the work for you, but it's hard to say for sure without knowing what data you have and what data you want. This query, as a start, would handle calculating the week numbers and working hours for you saving a fair bit of PHP code. SELECT tblUnitMaster.UnitID , WEEK(tblUnitMaster.SubmittalPromise,3) as SubmittalPromiseWeek , WEEK(NOW(),3) as CurrentWeek , tblUnitMaster.EngOpsEstHours - tblUnitMaster.Hours as WorkingHours , (tblUnitMaster.EngOpsEstHours - tblUnitMaster.Hours) / 3 as WeeklyHours FROM tblJobMaster LEFT JOIN tblUnitMaster ON tblJobMaster.JobNumber = tblUnitMaster.JobNumber WHERE tblJobMaster.Engineer = 'JBL' If you provide sample data and a clearer picture of your desired output perhaps someone can be of more assistance.
  4. Why do you need the local copies of the database rather than just interacting with the main database (either directly or via an API)?
  5. Not really. Your download link would just do the equivalent of adding the item to the cart then going to straight to the checkout page for the user to enter their payment information. Once the payment goes through successfully you'd then re-direct them somewhere to download the song.
  6. You'd have to see what tools you have available from your payment system. For example one could do a request to begin the transaction and get a payment transaction ID then update your database with that ID. After that commit the payment transaction and update your db. Finally remove the item from the processing queue. If there is a failure and the item is re-added to the queue then when it's processed again you can first check the database for the transaction ID. If one exists, query the payment provider to find the state of that transaction. If it is still pending then try and commit it again. If it's complete update your DB. If it's not found either try again or send the item out to a person for further investigation and manual reconciliation. I'd check PHP's default_socket_timeout setting and try increasing it. It defaults to 60 seconds so that seems to line up with your observation.
  7. The documentation for rpoplpush explains some. If you just did the basic approach of push/pop from a single stack then the item could be lost without being processed if something were to happen during processing. while (null !== $rs=$redis->lpop('queue')){ DoStuff($rs); } Say DoStuff throws exception or the power fails in the middle of it. That item will have been removed from the queue but not successfully processed. By pushing the item into another list you can remove it from the queue and process it without risking loosing it. For example: while (null !== $rs=$redis->bRPopLPush('queue','processing',0)){ DoStuff($rs); $redis->lrem('processing', 1,$rs); } Here the item is removed from the queue then added to a processing list. The code then does what it needs to do and finally removes it from the processing list. If there were a problem or power failure the item is preserved in the processing list. You'd then have another process that periodically checks the processing list for items past a certain age and restore them to the queue so they can be re-processed.
  8. It's showing 2.2.8 because that is the version of the redis client you installed. You did that when you installed the php56u-pecl-redis.x86_64 package. Documentation is on Github for how to use it. If it installed correctly then according to the documentation that should work. You may need to restart your server and/or PHP for the change to take effect.
  9. A simpler solution would be to read the file content into an array using file, sort the data using usort and then print it using a simple loop. The compare function for usort would handle extracting the unit number from the strings and compare them to sort the data.
  10. Just to clarify something, as I'm not sure from your posts if you understand or not, an HTTP Server is a socket server. It's just a specific implementation that happens to use the HTTP protocol to communicate data between the client and the server. When dealing on the socket level all that exists is packets of data. Either data being sent or data being received. The protocol in use would determine what is considered a full request or response which might involve several actual data packets. As requinix what setup you choose mostly depends on what you'd consider to be an acceptable delay in either side receiving information. If you poll once every 5 minutes for example then you have to assume a full 5 minute delay for any data being sent between the computers. You might occasionally get data sooner but you can't rely upon it. If you maintain a persistent connection then you can get the data almost instantly, but you'll need to use extra resources and do some extra coding to maintain this persistent connection. If you were dealing with mobile users there might also be data and/or battery usage to consider when choosing the best setup but that's got it's own list of pros/cons. Polling every X minutes may use extra data constantly checking but conserve battery by allowing the device to enter low power mode, for example. Mostly just because it'll let you get going easier and faster. Handling sockets correctly can also be a bit involved though, especially if you get into dealing with blocking vs non-blocking sockets. For example using non-blocking sockets can help keep your program responsive by not waiting around for slow/hung clients but means attempts to read from or write to the socket may miss some data and you have to try again later. My chat example sort of handles this using read/write buffers. Essentially: For maximum easy: Run a script every X minutes with cron that talks to some standard web server For maximum control: Develop a custom server and client that can be run continuously. There are various middle-ground approaches depending on how much easy you want to trade for control.
  11. I created a chat server using sockets as an example for someone on IRC a few years back. It might be helpful as an example for you to see how to deal with sockets. If you decide to create your own server/client setup you should probably look into some libraries to help with development rather than trying to do it all from scratch as in my example.
  12. When you click the links they use some javascript to submit a form that causing the server to generate the CSV then when it's complete some more javascript submits a second form that does the actual download. You'll have to spend some time decoding how this works and build a script that can simulate the forms using PHP. Alternatively ask them if they provide any easier way to get the data. The product page for that logger has a link to some developer documentation regarding API's and the hobolink home page mentions calling them for information about web services.
  13. You could use array_fill_keys to build the second parameter to array_intersect_key easier for larger arrays. if($source['guid']) { $clients[]=array_intersect_key($source, array_fill_keys(['name','guid'], null)); } else { $servers[]=array_intersect_key($source, array_fill_keys(['name','ip','port','encrypt_key'], null)); }
  14. Rather than make a function to pull a single image from the post, you should make a function to pull all the images from the post and return them in an array. Within your template then you can use a foreach loop to go over the returned array and output a div for each one. function extractImages($content){ $dom = new DOMDocument(); $dom->loadHTML($content); $imageTags = $dom->getElementsByTagName('img'); $imageHtml = []; foreach($imageTags as $tag){ $imageHtml[] = $dom->saveHTML($tag); } return $imageHtml; } This function parses through the given content using DOMDocument to find the images. This is better as it actually parses the HTML properly rather than just doing a naive search. It does require the HTML to be reasonable well formed however to work. Once it has found the images it returns an array of the image html tags. You'd then re-write your template like so: <div class="project-slider-mask w-slider-mask"> <?php foreach (extractImages(get_the_content()) as $image): ?> <div class="w-slide"> <a href="<?=get_permalink()?>"><?=$image?></a> </div> <?php endforeach; ?> </div> This will use the function to find the individual images an then loop over them using foreach. For ever image found it will output the HTML contained within the loop.
  15. The point of his reply was that it's impossible to answer your question without knowing what editor application you are using. Every application will have a different way of accomplishing this, assuming it has a way at all. Ask complete questions and maybe you won't get your time wasted with sarcastic answers.
  16. What Jacques1 is suggesting is that your client(s) connect to the server then just wait. When something happens on the server that the client needs to know about the server will send a message to the client. Long polling and websockets are one way of handling when your client is a browser. When your client is a PHP script you could just open a socket using stream_socket_client and then wait for data using stream_select. ReactPHP is a framwork you could use to help code such a script. The best way to go tackle your problem will depend a lot of exactly what kind of communication you need between the server and client and how much control you have over both ends.
  17. Since they are required pretty much everywhere one might as well get in the habit of always using one. It can be nice to omit them when using PHP as a templating language, for example <?php foreach ($StaffList as $sta): ?> <tr> <td><?=o($sta['staffFullname'])?></td> <td><?=o($sta['staffUsername'])?></td> <td><?=o($sta['jobTitle'])?></td> <td><?=o($sta['permissionGroupName'])?></td> </tr> <?php endforeach; ?> I generally add them anyway out of habit but occasionally I'll forget and it's nice to not have PHP complain about it. Side-rant: People intentionally omitting semi-colons in Javascript due to the ASI feature annoys the crap out of me.
  18. You have to store the number somewhere on the server and use PHP to control access to it. Any javascript solution is unreliable and would only work for a single client. If you cannot use a database then that leaves you with storing the number in text file. You'll need to create a file with the starting number then write code that will read the current number, increment it, and write it back out to the file. During this read/write process you also need to lock the file to prevent concurrent script executions from interfering with each other. To do this you'll be using the fopen, fread, fwrite, rewind, ftruncate, flock, fflush and fclose functions. For example <?php $filename = 'counter.txt'; $fp = fopen($filename, 'r+'); if (!$fp){ die('Could not open file. Create it first.'); } echo 'Attempting to acquire lock'.PHP_EOL; if (flock($fp, LOCK_EX)){ echo 'Lock has been acquired'.PHP_EOL; $value = trim(fgets($fp)); rewind($fp); ftruncate($fp, 0); fwrite($fp, $value+1); echo 'Read value '.$value.'; Incremented value to '.($value+1).' and wrote it back'.PHP_EOL; echo 'Pausing for a while for testing'.PHP_EOL; sleep(10); fflush($fp); flock($fp, LOCK_UN); echo 'Lock has now been released'.PHP_EOL; } fclose($fp); echo 'Finished'.PHP_EOL; First the script opens the file containing the number for read/write access. Next it attempts to acquire an exclusive lock on the file. The script will pause on this line until the lock can be acquired. Once the lock is acquired it means that no other instances of the script can access the file until the lock is released (they will pause instead). After acquiring the lock we read the current value of the file. We then clear the file's existing contents by moving the pointer back to the start and truncating the file to 0 length. The new value is then written to the file. The sleep is there just for testing so you can try running multiple copies of the script and see how they wait on each other due to the locking. Next the file is flushed to disk and unlocked and closed so that other scripts can access it.
  19. Unless you perform a strict comparison (third parameter set to true) then PHP compares objects by checking each value. Comparing Objects In your cases all objects are instances of stdClass so they meet the same class requirement. After that it checks each key/value to see if they match. If you set the third parameter of in_array to true so it does a strict check then all three cases would be false because every value is it's own unique instance even if all the keys are the same. Array's work similarly for a comparison so it would also work even if you had not cast them to objects first.
  20. Something like this should handle a request to domainB by issuing a redirect to the domainA landing page. RewriteCond %{HTTP_HOST} ^(www.)?domainB.com$ RewriteRule (.*) http://www.domainA.com/domain-b-landing-page/$1 [R=301,L] It also preserves the path of the original request by appending it to the domainA url. For example `domainB.com/page` would go to `domainA.com/domain-b-landing-page/page`. If your path redirects do not match up like that then you'll have to do them as separate RewriteRule entries before your catch-all entry in order of most-specific to least-specific.
  21. Do you want to keep the separate domain URL's or do you want to just redirect to the one domain? In other words if someone goes to domainB.com should the browser continue to show domainB.com or switch to domainA.com/domain-b-landing-page?
  22. The script is not designed to be run directly, it's designed to be run via the DirectoryIndex directive in apache. If you just want to get it working to play with then just change $path = $_SERVER['REQUEST_URI']; to some static path (relative to document root) such as $path = '/';
  23. To use something like TWIG you need to do two things. First you need to learn how to integrate it into the PHP side of the site so you can render and output the templates. Second you need to learn the syntax twig uses to create templates. Twig has some guides for both if you read their documentation Re-working my directory index example results in this: .dirindex.php <?php //Composer require twig/twig require 'vendor/autoload.php'; $showHiddenFiles=false; $ICON_MAP = array( 'folder' => '/icons/folder.png', 'file' => '/icons/generic.png' ); if (isset($_GET['viewsource'])){ header('Content-type: text/html'); show_source(__FILE__); exit; } else { chdir($_SERVER['DOCUMENT_ROOT']); $path = $_SERVER['REQUEST_URI']; $query = $_SERVER['QUERY_STRING']; $path = str_replace('?'.$query, '', $path); $realPath = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR); $pathParts = explode('/', trim($path, '/')); foreach ($pathParts as $part){ $realPath .= DIRECTORY_SEPARATOR.$part; } $path=$realPath; if (!$path || strncmp($path, $_SERVER['DOCUMENT_ROOT'], strlen($_SERVER['DOCUMENT_ROOT']))){ die('Invalid path'); } $reqPath = substr($path, strlen($_SERVER['DOCUMENT_ROOT'])); if ($reqPath[0] != '/'){ $reqPath = '/'.$reqPath; } if (!is_dir($path) || !is_readable($path)){ die('Cannot access '.$path); } $folders = $files = array(); $dh = opendir($path); while (($entry=readdir($dh)) !== false){ $fpEntry = $path.DIRECTORY_SEPARATOR.$entry; if ($entry != '.' && $entry != '..'){ if (is_dir($fpEntry) && ($showHiddenFiles || $entry[0] != '.')){ $folders[] = array( 'name' => $entry, 'id' => sha1($fpEntry), 'lastModified' => filemtime($fpEntry), 'lastAccess' => fileatime($fpEntry), 'createdOn' => filectime($fpEntry), 'permissions' => fileperms($fpEntry), 'size' => filesize($fpEntry), 'extension' => '', 'icon' => $ICON_MAP['folder'] ); } else if (is_file($fpEntry)){ if ($showHiddenFiles || $entry[0] != '.'){ $files[] = array( 'name' => $entry, 'id' => sha1($fpEntry), 'lastModified' => filemtime($fpEntry), 'lastAccess' => fileatime($fpEntry), 'createdOn' => filectime($fpEntry), 'permissions' => fileperms($fpEntry), 'size' => filesize($fpEntry), 'extension' => ($ext=strtolower(strrchr($entry, '.'))), 'icon' => (isset($ICON_MAP[$ext]))?$ICON_MAP[$ext]:$ICON_MAP['file'] ); } } } } } if (!isset($_GET['S'])){ $S = 'name'; } else { $S = $_GET['S']; } $O = (isset($_GET['O']) && in_array($_GET['O'], array('D','A')))?$_GET['O']:'A'; function SortFiles($a, $b){ global $S, $O; $ret = 0; switch ($S){ case 'size': $ret=$a['size'] - $b['size']; break; case 'modified': $ret=$a['last-modified'] - $b['last-modified']; break; default: $ret=strcmp(strtolower($a['name']), strtolower($b['name'])); } return $O=='A'?$ret:($ret*-1); } usort($files, 'SortFiles'); usort($folders, 'SortFiles'); header('Content-type: application/xml'); //Create a loader which handles locating and loading the template contents $twigLoader = new \Twig_Loader_Filesystem(__DIR__); //Create an environment which handles processing the templates. Give it //the loader we created so it can find the templates. $twig = new \Twig_Environment($twigLoader); //Render the template. First parameter is the file name, second is the //variables you want to make available within the template echo $twig->render('.dirindex.xml.twig', [ 'reqPath' => $reqPath , 'S' => $S , 'O' => $O , 'pathParts' => $pathParts , 'folders' => $folders , 'files' => $files ]); .dirindex.xml.twig <?xml version="1.0" encoding="us-ascii"?> <?xml-stylesheet type="text/xsl" href="/templating/twig/.dirindex.xsl"?> <page title="Index of {{reqPath}}"> <header> <stylesheet href="/templating/twig/.dirindex.css" /> </header> <content> <directoryIndex directory="{{reqPath}}" sortColumn="{{S}}" sortDir="{{O}}"> <breadcrumbs> {% set prefix='/' %} {% for part in pathParts %} <crumb path="{{prefix}}{{part}}" label="{{part}}" /> {% set prefix = prefix ~ part ~ '/' %} {% endfor %} </breadcrumbs> <contents> {% for folder in folders %} <entry type="directory" name="{{folder.name}}" last-modified="{{folder.lastModified|date('r')}}" last-access="{{folder.lastAccess|date('r')}}" created-on="{{folder.createdOn|date('r')}}" permissions="{{folder.permissions}}" size="{{folder.size}}" icon="{{folder.icon}}" id="{{folder.id}}" /> {% endfor %} {% for file in files %} <entry type="file" name="{{file.name}}" last-modified="{{file.lastModified|date('r')}}" last-access="{{file.lastAccess|date('r')}}" created-on="{{file.createdOn|date('r')}}" permissions="{{file.permissions}}" size="{{file.size}}" extension="{{file.extension}}" icon="{{file.icon}}" id="{{folder.id}}" /> {% endfor %} </contents> </directoryIndex> </content> </page>
  24. What you want to do is separate your HTML and your PHP code as much as possible. For larger applications this probably would involve keeping the HTML in a separate file and using a template engine such as TWIG to process it and render the final result. For smaller single-page scripts you can generally keep all your PHP code at the top and the HTML at the bottom, possibly using functions to create separate re-usable blocks of HTML. Your specific example isn't really enough to give much advice. One alternative way to write it is this: <?php // I am assuming these are something you gather from a database or somewhere $rooms = [1,2,3,4]; $displayed = 2; //-------- ?> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script> <script type="text/javascript"> $(document).ready(function(){ $('#room').change(function(){ $(this).parent('form').submit(); }); }); </script> <div> <form id='form1' action='#' method='post'> <select name='room' id='room'> <?php foreach ($rooms as $room): ?> <option value="<?=htmlspecialchars($room)?>" <?=($displayed==$room)?'selected':''?> ><?=htmlspecialchars($room)?></option> <?php endforeach; ?> </select> <noscript><input type='submit' value='Submit'></noscript> </form> </div> I'm assuming the $rooms and $displayed variables are coming from somewhere and not just statically set like that. When I mix HTML and PHP I prefer to use the alternative syntax for control structures as I find it much more readable. I also prefer the short syntax for echoing out variables for the same reason. As a more complete example here is a script I created years ago to list the files in a directory. At one point in the past I had a directory on my server that I'd just drop lots of example/test scripts in and need it to be browsable so I setup the following as my DirectoryIndex file for that folder. <?php $showHiddenFiles=false; $ICON_MAP = array( 'folder' => '/icons/folder.png', 'file' => '/icons/generic.png' ); if (isset($_GET['viewsource'])){ header('Content-type: text/html'); show_source(__FILE__); exit; } else { chdir($_SERVER['DOCUMENT_ROOT']); $path = $_SERVER['REQUEST_URI']; $query = $_SERVER['QUERY_STRING']; $path = str_replace('?'.$query, '', $path); $realPath = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR); $pathParts = explode('/', trim($path, '/')); foreach ($pathParts as $part){ $realPath .= DIRECTORY_SEPARATOR.$part; } $path=$realPath; if (!$path || strncmp($path, $_SERVER['DOCUMENT_ROOT'], strlen($_SERVER['DOCUMENT_ROOT']))){ die('Invalid path'); } $reqPath = substr($path, strlen($_SERVER['DOCUMENT_ROOT'])); if ($reqPath[0] != '/'){ $reqPath = '/'.$reqPath; } if (!is_dir($path) || !is_readable($path)){ die('Cannot access '.$path); } $folders = $files = array(); $dh = opendir($path); while (($entry=readdir($dh)) !== false){ $fpEntry = $path.DIRECTORY_SEPARATOR.$entry; if ($entry != '.' && $entry != '..'){ if (is_dir($fpEntry) && ($showHiddenFiles || $entry[0] != '.')){ $folders[] = array( 'name' => $entry, 'full-path' => $fpEntry, 'last-modified' => filemtime($fpEntry), 'last-access' => fileatime($fpEntry), 'created-on' => filectime($fpEntry), 'permissions' => fileperms($fpEntry), 'size' => filesize($fpEntry), 'extension' => '', 'icon' => $ICON_MAP['folder'] ); } else if (is_file($fpEntry)){ if ($showHiddenFiles || $entry[0] != '.'){ $files[] = array( 'name' => $entry, 'full-path' => $fpEntry, 'last-modified' => filemtime($fpEntry), 'last-access' => fileatime($fpEntry), 'created-on' => filectime($fpEntry), 'permissions' => fileperms($fpEntry), 'size' => filesize($fpEntry), 'extension' => ($ext=strtolower(strrchr($entry, '.'))), 'icon' => (isset($ICON_MAP[$ext]))?$ICON_MAP[$ext]:$ICON_MAP['file'] ); } } } } } if (!isset($_GET['S'])){ $S = 'name'; } else { $S = $_GET['S']; } $O = (isset($_GET['O']) && in_array($_GET['O'], array('D','A')))?$_GET['O']:'A'; function SortFiles($a, $b){ global $S, $O; $ret = 0; switch ($S){ case 'size': $ret=$a['size'] - $b['size']; break; case 'modified': $ret=$a['last-modified'] - $b['last-modified']; break; default: $ret=strcmp(strtolower($a['name']), strtolower($b['name'])); } return $O=='A'?$ret:($ret*-1); } usort($files, 'SortFiles'); usort($folders, 'SortFiles'); header('Content-type: application/xml'); ?> <?xml version="1.0" encoding="us-ascii"?> <?xml-stylesheet type="text/xsl" href="/extras/.dirindex.xsl"?> <page title="Index of <?=htmlspecialchars($reqPath);?>"> <header> <!--<script href="/extras/.dirindex.js" />--> <stylesheet href="/extras/.dirindex.css" /> </header> <content> <directoryIndex directory="<?=htmlspecialchars($reqPath);?>" sortColumn="<?=htmlspecialchars($S);?>" sortDir="<?=htmlspecialchars($O);?>"> <breadcrumbs> <?php $prefix='/'; foreach ($pathParts as $part): ?> <crumb path="<?=htmlspecialchars($prefix.$part);?>" label="<?=htmlspecialchars($part);?>" /> <?php $prefix .= $part.'/'; endforeach;?> </breadcrumbs> <contents> <?php foreach ($folders as $folder): ?> <entry type="directory" name="<?=htmlspecialchars($folder['name']);?>" last-modified="<?=htmlspecialchars(date('r', $folder['last-modified']));?>" last-access="<?=htmlspecialchars(date('r', $folder['last-access']));?>" created-on="<?=htmlspecialchars(date('r', $folder['created-on']));?>" permissions="<?=htmlspecialchars($folder['permissions']);?>" size="<?=htmlspecialchars($folder['size']);?>" icon="<?=htmlspecialchars($folder['icon']);?>" id="<?=htmlspecialchars(sha1($folder['full-path']));?>" /> <?php endforeach;?> <?php foreach ($files as $file): ?> <entry type="file" name="<?=htmlspecialchars($file['name']);?>" last-modified="<?=htmlspecialchars(date('r', $file['last-modified']));?>" last-access="<?=htmlspecialchars(date('r', $file['last-access']));?>" created-on="<?=htmlspecialchars(date('r', $file['created-on']));?>" permissions="<?=htmlspecialchars($file['permissions']);?>" size="<?=htmlspecialchars($file['size']);?>" extension="<?=htmlspecialchars($file['extension']);?>" icon="<?=htmlspecialchars($file['icon']);?>" id="<?=htmlspecialchars(sha1($folder['full-path']));?>" /> <?php endforeach;?> </contents> </directoryIndex> </content> </page> As you can see all the work of finding the files and sorting them is done at the top. The bottom is the generated XML with just a few loops and echos, nothing complicated.
  25. You should not be logging a plain-text password regardless of whether it's valid or not. A key point from the above Q/A: self is a keyword that references the same class the method is defined in. It's just an easy way to reference the class without having to do so by it's specific name. For example you could do new self() within a method to create a new instance of the class or specify a method takes an instance of itself as an argument via function compare(self $other){ ... }. The line above self says Class/interface name, that is the relevant line. It means you can use any class or interface name as a type hint. Something like this: class LoginAttemptsLog { public function validLogin($username){ $this->logAttempt($username, '***', 1); } public function invalidLogin($username, $password){ $this->logAttempt($username, $password, 0); } private function logAttempt($username, $password, $isValid){ $sql = "INSERT INTO user_login (login_status, login_ip, login_username,login_password, login_datetime) values(?, INET_ATON(?), ?, ?, NOW())"; $stmt = $this->pdo->prepare($sql); $stmt->execute(array( $isValid, $_SERVER['REMOTE_ADDR'], $username, $password )); } }
×
×
  • 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.