-
Posts
4,704 -
Joined
-
Last visited
-
Days Won
179
Everything posted by kicken
-
Executing time consuming functions in an EventLoop
kicken replied to NotionCommotion's topic in PHP Coding Help
Indeed, This is why you don't just load up the queue with a simple foreach loop. Instead you have your callback re-register itself as long as there is stuff to do. This works out because the queue will only run whatever callbacks were registered at the time it started running. Any newly added callbacks will be delayed until the next event loop cycle. If there are any callbacks in the future tick queue you can see that the event loop will set it's timeout to zero so that it won't block. It does still test for stream activity so it will still be able to dispatch and process incoming I/O as it needs it, it just won't wait around for it. -
Executing time consuming functions in an EventLoop
kicken replied to NotionCommotion's topic in PHP Coding Help
Ideally you don't ever block if you have work to do. In general, as long as you can do work you should be doing work. It's when you cannot do any work that you want to yield control to the event loop. That's usually when you're waiting for I/O from somewhere. That said, if the work you can do is going to take along time without having any sort of natural blocking point (I/O) but you don't want to block your other tasks for that long then you need to start trying to find ways you can break up that task so you can yield control occasionally. That's generally known as cooperative multitasking. In the case of sending a bunch of emails, an obvious way to break that up would be to yield control after each email. If other tasks are pending in the queue then they will get a chance to do their work. If not, control will return back to your original task immediately. The only time the process should be blocked is when either there are no tasks at all or all tasks are waiting on I/O. I haven't done anything with react in a long time but as far as I can tell what you'd want to do is use the futureTick function to schedule more work and break up your task. For example: <?php class EmailQueue { private $loop; private $emailList; private $isTicking; public function __construct(LoopInterface $loop){ $this->loop = $loop; $this->index = 0; $this->emailList = new SplQueue(); $this->isTicking = false; } public function queueEmail(string $to, string $message){ $this->emailList->enqueue([$to, $message]); if (!$this->isTicking){ $this->tick(); } } private function tick(){ if ($this->emailList->isEmpty()){ $this->isTicking = false; } else { $this->isTicking = true; $this->loop->futureTick(function(){ $this->processMessage(); $this->tick(); }; } } private function processMessage(){ [$to, $message] = $this->emailList->dequeue(); //Send message. } } $loop = Factory::create(); $queue = new EmailQueue($loop); //load up the queue with a bunch of emails. $loop->run(); When you first queue up an email, it will call the tick() function. That function will check if there are any messages in the queue. If there are it registers a callback to be executed on the next cycle of the event loop. When that callback is executed it will dequeue one message and send it, then call tick() again which causes the cycle to repeat if necessary. As long as there is email in the queue this will constantly work through the queue while still allowing the loop to trigger other work items. -
var jsonObj = request.result; This sets jsonObj to undefined because XMLHttpRequest doesn't have a result property. You need to read and parse the responseText property. XMLHttpRequest is an older standard. You might also want to look at the more modern fetch() API instead.
-
Your starting array is in a strange format. You have your outer array with 3 sub-array lists. Each element in that sub-list is then a single-item array with an index matching it's parent index. I'd probably see if that can be cleaned up and better organized first if possible. The code would end up cleaner and easier to understand if you could remove one or two of those levels. It seems like you could probably just form one single list instead of the nested setup you have now. For example: array ( 0 => array ( 'dataAula' => '2020-09-21', 'tempos' => '4', 'tempos2' => 'Segunda', 'total' => 4, ), 1 => array ( 'dataAula' => '2020-09-22', 'tempos' => '4', 'tempos2' => 'Terça', 'total' => 8, ), //... ); At the vary least it should be possible to remove the third level of the array you currently have. That said, what you want to do is possible with your setup. You need another loop though as you need to loop over the outer array first. Each item of that loop is another array you need to loop over. Each item of that inner loop is another single-element array that you need to "unwrap" so to speak to get access to the data. $result = []; //Loop over list $array, each item of which is another list. foreach ($array as $level1){ //Loop over the sub-list. foreach ($level1 as $level2){ //$level2 is a single-element array with the same index as it's parent. Extract that single element. $level2 = current($level2); $date = $level2['dataAula']; if (isset($result[$date])){ $result[$date]['tempos'] .= '+' . $level2['tempos']; } else { $result[$date] = $level2; } } }
-
Yes, I did this year ago also just like you. As I said though, this is something that has never been officially supported in any way, nor has it ever been reliable. I understand what you want. You want your loading gif to appear immediately and then your script continue and outputting updates as it goes. Whether that will work or not depends on a lot of things outside of PHP's control so it's not something you can rely on. The proper way to do something like that is to load a simple page first, then use javascript to update it over time. This will probably require re-working your script to run over multiple requests and do the work in the background some way. Either that or just put a notice up that it might take a while and do without any kind of progress indication. If you have some prior page that links to your script, you can have it display the loading indicator prior to making the request. The browser should leave it up until the request is complete.
-
You're attempting to do something that's always been a fundamentally flawed idea. That fact that it may have worked before comes down mostly to luck/implementation details and not because if was ever an officially supported feature. ob_flush/flush does still make PHP send it's output. The problem (then and now) is that there might be other buffers in the chain that PHP has no way to control such as you web-server's buffer, a caching proxy server buffer, the browser's buffer, etc. If you want some kind of a loading animation for your page, you need to output a page that's just your loading animation and then use Javascript to fill in the content after by loading it in the background using ajax / fetch().
-
The delimiters don't matter really, though by using # you could skip escaping the / in the expression. Normally I'd probably use something other than / as well in a situation like this just to avoid that escape, but I was to lazy to change them on the website. You need the start and end of string anchors though if you want to enforce the value strictly. Without them it just looks for the pattern somewhere in the string, not that the string is exactly that pattern. So your regex would also match if: $_POST['ay'] = 'I want to attend in the (2020/21) academic year';
-
If you want the entire string to be in that format, you need to use the start (^) and end ($) anchors and put your pattern in between. Your regex currently also only looks for digits and /, but they can be in any order. If you want to enforce that strict format you need to look 4 digits followed by a slash followed by 2 more digits. Given the above, you end up with a regex such as /^\(\d{4}\/\d{2}\)$/
-
When you're trying to re-create a flow, the best thing to do generally is to use either the browsers developer tools or something like fiddler to monitor what exactly the requests being made are, then figure out how to re-create those requests. Sometimes it's as simple as loading a URL, other times it's more complicated and involves parsing the previous pages source for various details. The process is something you general have to figure out on a case-by-case basis so it'll be difficult for anyone to really guide you without at lot of details.
-
shell_exec doesn't seem to work on hosted server (Bluehost)
kicken replied to KenHorse's topic in PHP Coding Help
Trying to run your other script with shell_exec just introduces unnecessary complexity to the problem. Since your script is just another PHP script (and a simple one at that) then you can just include() it to run it. if (isset($_POST['clearflags'])){ include 'clearflags.php'; } You shouldn't be messing with the shell functions unless you need to run some external non-php program or some other php application that's intended to be run standalone from the command like (ie, composer). -
Perhaps if you check the manual, you can find the function you need.
-
Notice: Undefined index: driving me insane
kicken replied to Beauford2016's topic in PHP Coding Help
Undefined index (as specified in your title) refers specifically to array indexes, not variables in general so code like you posted wouldn't really help any. The common scenario where you encounter this is with the input arrays $_POST, $_GET, etc as what they contain depends on the request. Since you can't be certain whether a given key exists in those arrays, you should always be checking for it and providing a sensible fall-back value if it doesn't. With PHP 7 this has been made easy by using the null coalesce operator. In older versions you'd have to use isset() to check. There are other less common scenarios where the indexes of an array may or may not exist, but the results of a database query (implied in the question) generally isn't one of them. You should know what you're selecting and whatever you're selecting is what will be defined in your array. So the answer to your in general inquiry is that you generally should know whether or not a given index will be defined in an array. If it will 100% for sure be defined then you should not have an issue with this error. If you're unsure then you need to either find out, or code around the possibility that it doesn't exist by using either the null coalesce operator or isset(). One thing I do to handle this with regard to $_POST is define exactly what indexes I expect to exist and initialize them to null using array_fill_keys, then I replace the null values with whatever was in $_POST. Then I know the keys I am interested in will exist, but might be null. $data = array_fill_keys(['first','last','email'], null); $data = array_replace($data, array_intersect_key($_POST, $data)); // Now $data['first'], $data['last'], and $data['email'] are guaranteed to exist. -
When I started out with PHP I'd always use a simple PHP array in a file and include that file, as demonstrated above. This is very simple and easy to use. One thing that can be both a benefit and a detriment of this is that the configuration is PHP code. One the plus side, you can use the code to do some fancy stuff. On the down side, allowing code to run in the configuration could cause problems. Typos for example could cause the whole application to break. As with most people, I eventually moved toward JSON for my configuration files. The format works well for simple data and is less susceptible to problems. There's no possibility to inject code via the configuration. Typos may cause issues, but they can be detected and handled gracefully when parsing the file rather having it break the entire application. As you mentioned though, comments in the file are not supported by default though which is annoying for various reasons. After having used Symfony for a while, I like the YAML format and would probably consider it for future projects. It's not natively supported which is a bit of a bummer, but with any reasonably side project you'd likely have other library requirements anyway. In all cases, I try and keep the configuration file as small and simple as possible. If the project involves a database, I will generally store as much configuration data in the database as possible. Having it in the database allows for easier manipulation of the configuration through the application such as a settings page or similar. The configuration file often ends up only needing to store the database connection details.
-
I don't think it is possible. I can't see how the code would possibly work in production either if it's trying to declare a class twice. Only thing I can think of is the problem was fixed but that fix didn't make it into the version you have. One way to try and deal with it while still being able to track you changes reasonably well would be to create a branch that has all the changes needed just to get the application working. Then create a new branch from that to do your debugging on. When done you can diff the two branches.
-
I showed you everything you need to know to figure out it out my first post. I showed you how you can replace t3_home with a variable called key. I showed you how you can construct a variable named key from some strings and another variable containing a number. Put those together and you have your answer for how to add your x variable into that command. You can then extrapolate from that and figure out how to make your home part into a variable also.
-
The query just asks the database for information matching your criteria. After you run the query you need to fetch the data to make use of it. If nothing matches your criteria, you'll know because your attempt to fetch the data will return false instead of usable data.
-
So make it a variable also and concatenate it as well just like was done with the 3.
-
Javascript allows an object's properties to be accessed using array notation as well, so you can use either document.freeone.t3_home or document.freeone['t3_home'] to access the t3_home property. Array notation allows the use of variables as the index value, so you can do something like this: var key = 't3_home'; document.freeone[key].value = 'close'; Now all you have to do is construct the appropriate value for the key variable, which can be done using simple concatenation. var x = 3; var key = 't'+x+'_home';
-
PHP is the wrong tool for the job. If the form she has to fill in is within a web browser then you could use what's known as a bookmarklet to do the job. You need to identify the inputs using the developer tools. If they have an ID then life is fairly easy. Your bookmarklet would just be code like: javascript:document.getElementById('session-input-id-here').value='her-session-id';document.getElementById('password-input-id-here').value='her-session-password';void(0); You'd create a new bookmark in your browser and put that in for the bookmark's URL/Location. Replace the values appropriately. Then after loading the page with the form you can just click the bookmark to fill in the values. If the form is part of a desktop application then you might need to use something like AutoHotKey to do the job. I'm less familiar with this as I don't really use it, just know it exists and should probably work.
-
Small rant thread for some recent frustrations. So a friend of mine has a few sites she has been trying to run using a third-party system she bought. I've been providing some hosting for her for free on my VPS to help her save some money. The software she has is kind of junk by modern standards I think. Uses Zend Framework v1 and was probably written in the early php 5.x days originally. For some reason she likes it even though she seems to be constantly opening support tickets for things. Support was always slow to respond too and used to always complain that they couldn't access the site and work on it because I didn't have cPanel and phpMyAdmin setup. Been better about that lately, I guess they got someone who knows how to use SFTP/SSH working there finally. Recently she decided to buy their upgraded version for a new site. Being a new major version I had hoped the code behind it had been improved but it doesn't seem that's the case. I got it setup for her and she started trying to configure/customize it and ran into some issues almost immediately and opened tickets. Rather than try and address the issue this time though they just responded: Version is too high? Really? 😒 The server is setup for PHP 7.3.21. The 7.3 branch isn't exactly cutting edge, I'd like to think a vendor selling still-updated software would support that. They apparently only support 7.2 according to the requirements list they sent along. Whatever though, I went ahead and downgrade her site for her to 7.2. I include a little note for her to forward to their support though expressing my frustration: In the end they end up doing a re-install of the software for her and she starts over. Ticket resolved. Fast forward a few days, she submits a new ticket and again they decide to complain about the hosting setup. This time: I have the server setup using PHP-FPM so each site can run under the appropriate user account rather than www-data. Much nicer setup IMO and shouldn't make any difference. As far as I can tell, the only thing affected in their application by not being run as an Apache module is that their installer script can't verify if mod_rewrite is enabled or not. The script just says 'Unable to check' and shows it as a warning, you can still continue and install anyway. I told her I wasn't going to change this. They can just deal with it, and if they won't then she might just have to look at some of their recommended hosting. She's still working on the site so I'm guessing they decided to deal with it. Hopefully they are done blaming the hosting setup now, but who knows.
-
Yes, from all the ones you are using as an include file. Those parts of the code should only exist once in your page. You already have them in your PHP file so you don't want them in your html files as well.
-
Because the problem isn't in your PHP code, it's in your included .html files. I actually went to the URL from your screenshot and looked at the site before posting, not just at the code here. You can see the problem if you just load your HTML file directly in the browser and exclude the PHP file entirely. The direct cause of the content not displaying is the error in your script tag as I said. However, as I also said, your .html files are incorrect for use as an include file as they contain all the boilerplate html markup which should NOT be there when the content is included into another page. Your 268.html file should contain only this content: <p> Yea, hath God said? Gen. 3:1<br> <br> When the tempter came to Jesus, he said, If thou be the Son of God. Matt. 4:3<br> <br> Jesus said unto him, It is written.... it is written... it is written. Matt. 4:4, 7, 10<br> <br> Then the devil leaveth him. Matt. 4:11<br> <br> I may not return with thee. For it was said to me by the word of the LORD, Thou shalt eat no bread nor drink water there. He said unto him, I am a prophet also as thou art; and an angel spake unto me by the word of the LORD, saying, Bring him back with thee into thine house, that he may eat bread and drink water. But he lied unto him. So he went back with him. The man of God.... was disobedient unto the word of the LORD: therefore the LORD hath delivered him unto the lion, which hath torn him, and slain him, according to the word of the LORD. I Kings 13:16-19 & 26<br> <br> Though we, or an angel from heaven, preach any other gospel unto you than that which we have preached unto you, let him be accursed. Gal. 1:8<br> <br> Thy word have I hid in mine heart, that I might not sin against thee. Psa. 119:11 </p> None of that boilerplate code. So what you should be doing is going through all your .html files and removing all that extra code.
-
Yes. You're issue isn't that the people here don't know what they are doing, the problem is you keep changing things and understanding how it affects the code. The code you had in your original post in the original thread was fairly close to correct. Requinix said what you needed to do to fix it (by saying what you need to do, not just giving you the code to do it) but I guess you didn't understand or something. Then you changed the code to something else which invalidated that advice and started you down a different path. So let's just back the f* up and go back to that original code with your checkboxes as a simple array. <input type="checkbox" name="fruit_selection[]" value="fruit_apple"> <input type="checkbox" name="fruit_selection[]" value="fruit_orange"> <input type="checkbox" name="fruit_selection[]" value="fruit_banana"> <input type="checkbox" name="fruit_selection[]" value="fruit_pear"> <input type="checkbox" name="fruit_selection[]" value="fruit_kiwi"> What this will do is create an array when submitted called $_POST['fruit_selection'] The contents of this array will be the choices that the user selected. The items that were not selected will not exist in the array. Your original code seems to indicate you almost understood this as you were checking for $_POST['fruit_selection'][0] and so on. What you seemingly failed to understand is that element [0] in that array does not equate to the checkbox with "fruit_apple", it equates to whichever is the the first checkbox the user actually checked is (which could be fruit_kiwi for example if they only checked the last one). So what you want to do to get your 1/0 values it not check of those positions in the array exist, but check if the values of your checkboxes exist within that array. This is what requinix was telling you to do. One way to do that is using php's in_array function. For example. $isKiwiChecked = in_array('fruit_kiwi', $_POST['fruit_selection']); Now you should have enough information to figure everything out. So take a time out and spend some time learning rather than blaming everything on the people attempting to help you being idiots. Use things like var_dump as demonstrated above to get an idea of what data you have available and what format it's in so you can better learn what to do.
-
Notice how after your devotional div you have another DOCTYPE and begining of an HTML document? That's not correct. The doctype and all that stuff in the <head> should only ever appear once in a page. Your include file apparently has another copy of it that you need to remove. This appears to be a problem not only in the file that doesn't display, but also in your other files that do work. All the .html files you're including as content into the page should contain only the HTML content to be displayed and not all the other page structure (doctype, head, body tags, etc). As for why you see no content on the one page, notice that your <script> tag is incomplete? It ends with type= but then cuts out without being closed. That is why your content doesn't display as the browser thinks it's all part of the script tag. The fix for this would normally be to finish your script tag, like you did in your other files. However, in your case you want to just remove all this code as mentioned above.
-
In your particular use case, there may not be a real downside, but that doesn't hold true for all use cases and the operation in general is wrong. That's why the warning exists. When PHP needs to do a string to integer conversion, but the string is not a valid integer you end up with zero. In your case, that's probably what you want to happen so it "works". It's a sign of possible bug though so the warning is there to alert you to check your code. The proper thing to do is first validate your input so you know it's a valid number, and maybe even convert it yourself while your at it. As I mentioned, this could potentially be easily done with a simple array_map operation depending on your input needs. If all your inputs should be numbers, you could do something like this: $data = array_map('floatval', $_POST); Then just use $data['blah'] in your calculations. Any empty strings (or invalid numbers) will have been converted to zero, and any valid numbers will have been converted to a really number type. If only some of your inputs need to be converted, then you can do similar to the above, but limit the scope to the necessary inputs using array_intersect_key. $data = array_map('floatval', array_intersect_key($_POST, array_flip(['list','your','input','names','here']))); Yet another alternative is to create a function to grab your input values and let it handle the conversion. function getInputNumber($field){ return floatval($_POST[$field] ?? 0); } Bottom line is there are many ways to solve the empty string problem without having to do a massive amount of code modifications. The changes required could be nearly none (if you say re-assign $_POST) or easily handled via a find/replace function in your editor.