emGee Software Solutions Custom Database Applications

Share this

Planet PHP

People blogging about PHP
Updated: 1 week 17 hours ago

Ketting 2.3 release - Evert Pot

Thu, 10/11/2018 - 09:00

I just released Ketting 2.3, the missing HATEOAS client for Javascript.

I last blogged about this project in June, so I thought it was worth listing the most interesting recent changes.

Content-Type and Accept header improvements

In the past, the Ketting library used a configurable set of mime-types for the Accept header, and some heuristics for the Content-Type headers. This has been greatly improved.

If you’re following links in this format:

{ "_links": { "next": { "href": "/next-hop", "type": "application/vnd.some-vendor+json"} } } <link rel="next" href="/next-hop" type="application/vnd.some-vendor+json" /> HTTP/1.1 200 OK Link: </next-hop>; rel="next" type="application/vnd.some-vendor+json"

In each of those cases, the link embeds a hint for the content-type at this new location.

When running the following on a resource, the GET request will now automatically use that value fo the Accept header:

const resource = "..."; // Pretend this is a Ketting resource. const nextResource = await resource.follow('next'); console.log(await nextResource.get()); // Will get a application/vnd.some-vendor+json Accept header. Support for OAuth2 client_credentials grant

The library supported some OAuth2, specifically:

  • Simply supplying a Bearer token.
  • Using the password grant_type.

Now, the library also supports the client_credentials grant. The library now also detects if no refresh_token was given, and will automatically re-authenticate using the original grant_type, if this was the case.

No longer ships with a fetch() polyfill

When using the web-packed file, I noticed that a large part of the size of the Ketting library was attributable to a polyfill for the Fetch API.

Every modern browser ships the Fetch API, so this no longer seemed needed. If you do need to run Ketting on an older browser, you can simply provide your own polyfill, such as the whatwg-fetch package.

Updating

For well-behaved servers, these changes should not have a negative impact. Don’t forget to test.

To update, this should usually do it:

npm install ketting@2.3.0
Categories: Web Technologies

Avoiding Setter Injection - Brandon Savage

Thu, 10/11/2018 - 06:00

PHP more or less has two kinds of dependency injection available: constructor injection, and setter injection. Constructor injection is the process of injecting dependencies through the constructor arguments, like so: The dependencies are injected via the constructor, on object creation, and the object has them from the very beginning. Setter injection is different; instead of […]

The post Avoiding Setter Injection appeared first on BrandonSavage.net.

Categories: Web Technologies

PHP 7.1.23 Released - PHP: Hypertext Preprocessor

Wed, 10/10/2018 - 17:00
The PHP development team announces the immediate availability of PHP 7.1.23. This is a bugfix release.All PHP 7.1 users are encouraged to upgrade to this version.For source downloads of PHP 7.1.23 please visit our downloads page, Windows source and binaries can be found on windows.php.net/download/. The list of changes is recorded in the ChangeLog.
Categories: Web Technologies

PHP 7.3.0RC3 Released - PHP: Hypertext Preprocessor

Wed, 10/10/2018 - 17:00
The PHP team is glad to announce the next PHP 7.3.0 pre-release, PHP 7.3.0RC3. The rough outline of the PHP 7.3 release cycle is specified in the PHP Wiki. For source downloads of PHP 7.3.0RC3 please visit the download page. Windows sources and binaries can be found on windows.php.net/qa/. Please carefully test this version and report any issues found in the bug reporting system. THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION! For more information on the new features and other changes, you can read the NEWS file, or the UPGRADING file for a complete list of upgrading notes. Internal changes are listed in the UPGRADING.INTERNALS file. These files can also be found in the release archive. The next release would be RC4, planned for October 25th. The signatures for the release can be found in the manifest or on the QA site. Thank you for helping us make PHP better.
Categories: Web Technologies

PHP 7.2.11 Released - PHP: Hypertext Preprocessor

Wed, 10/10/2018 - 17:00
The PHP development team announces the immediate availability of PHP 7.2.11. This is a bugfix release.All PHP 7.2 users are encouraged to upgrade to this version.For source downloads of PHP 7.2.11 please visit our downloads page, Windows source and binaries can be found on windows.php.net/download/. The list of changes is recorded in the ChangeLog.
Categories: Web Technologies

304 Not Modified - Evert Pot

Tue, 10/09/2018 - 08:00

304 Not Modified is used in response to a conditional GET or HEAD request. A request can be made condtional with one of the following headers:

  • If-Match
  • If-None-Match
  • If-Modified-Since
  • If-Unmodified-Since
  • If-Range

If-Modified-Since and If-None-Match are used specifically to allow a client to cache results and asks the server to only send a new representation if it has changed.

If-Modified-Since does this based on a Last-Modified header, and If-None-Match with an ETag.

Example

A client does an initial request:

GET /foo HTTP/1.1 Accept: text/html

A server responds with an ETag:

HTTP/1.1 200 Ok Content-Type: text/html ETag: "some-string"

The next time a client makes a request, it can include the ETag:

GET /foo HTTP/1.1 Accept: text/html If-None-Match: "some-string"

If the resource didn’t change on the server, it can return a 304.

HTTP/1.1 304 Not Modified ETag: "some-string" References
Categories: Web Technologies

Http errors package for Typescript - Evert Pot

Wed, 10/03/2018 - 08:00

Hacktoberfest 5 has begon, and as my first contribution I wanted to make a tiny Typescript library with HTTP errors.

Whenever I start a new Javascript-based project, whether that’s on the server, or if I’m writing an API client with Fetch, I often find myself do the same thing over and over again, which is to define a simple set of exceptions representing HTTP errors, like this:

class NotFound extends Error { httpStatus = 404; }

A bit fed up with this, I decided to make a small package that’s just a list of errors for Typescript, along with some tiny utilities.

Example:

import { NotFound } from '@curveball/http-errors'; throw new NotFound('Article not found');

The idea is that the interface is really just this:

export interface HttpError extends Error { httpStatus: number; }

Which means that any error with a httpStatus property automatically follows this pattern, and generic middlewares can be written to listen for them.

It comes with a simple utility function to see if the Error conforms with this pattern:

import { isHttpError } from '@curveball/http-errors'; const myError = new Error('Custom error'); myError.httpStatus = 500; console.log(isHttpError(myError)); // true Problem+json

A great idea for emitting errors from a HTTP API is to use the application/problem+json format, defined in RFC7807. The package also contains a few utilities to help with these:

export interface HttpProblem extends HttpError { type: string | null; title: string; detail: string | null; instance: string | null; }

Every standard exception that ships with this package also implements this interface. Most properties (except title) default to NULL as they are likely applicatio

Truncated by Planet PHP, read more at the original (another 3508 bytes)

Categories: Web Technologies

303 See Other - Evert Pot

Tue, 10/02/2018 - 08:00

303 See Other can be used to tell a client that the result of the operation can be found on another location.

For example, if a client did a POST request, a server might immediately respond to that POST request with a response body, for example to inform the client or user that the operation was successful.

It’s sometimes better to not do that, and immediately redirect the user to a new page instead. One reason is that in browsers, it messes with the “back” button and will ask the user to submit the a form again. When redirecting immediately, browsers don’t do this and this is extremely common practice.

So 303 means that the server is not immediately returning a result, but it instructs the client to go look somewhere else to get the result. The client must use a GET request for this.

Most webservices and server frameworks incorrectly use the 302 Found status-code for this instead.

Example HTTP/1.1 303 See Other Server: Curveball/0.4.0 Location: /confirmation References
Categories: Web Technologies

Test-driving repository classes - Part 2: Storing and retrieving entities - Matthias Noback

Tue, 10/02/2018 - 07:05

In part 1 of this short series (it's going to end with this article) we covered how you can test-drive the queries in a repository class. Returning query results is only part of the job of a repository though. The other part is to store objects (entities), retrieve them using something like a save() and a getById() method, and possibly delete them. Some people will implement these two jobs in one repository class, some like to use two or even many repositories for this. When you have a separate write and read model (CQRS), the read model repositories will have the querying functionality (e.g. find me all the active products), the write model repositories will have the store/retrieve/delete functionality.

In particular if you write your own mapping code (like I've been doing a lot recently), you need to write some extra tests to verify that the persistence-related activities of your repository function correctly.

Writing tests for store and retrieve actions

When you're testing a class, you're actually specifying its behavior. But you're doing that from an outsider's perspective. The test case uses an instance of your class (the subject-under-test). It calls some methods on it and checks if the resulting behavior is as expected.

How would you specify the behavior of a save() method? You could say about the repository: "It can save an entity". How would you verify that a given repository class implements this specification correctly? If the repository would use Doctrine ORM, you could set up a mock for the EntityManager or a similar class/interface, and verify that it passes the object to its persist() method. However, as explained earlier, within repository classes mock's aren't allowed. The other option would be to make a call to that save() method and afterwards look inside the database to verify that the expected records have been inserted. However, this would tie the test to the implementation of the repository.

It seems there's no easy way in which you can find out if a call to save() has worked. But let's think about that save() method. Why is it there? Because we want to be able to later retrieve the entity that it saves. So, what if we test our save() method by also introducing its counterpart, getById()? That way, we can indirectly find out if save() has worked: getById() is expected to return an object that's equal to the object you've just persisted.

In other words, a black box test for save() can be written if you combine that test with getById():

public function it_can_save_and_retrieve_an_entity(): void { // Create a basic version of the entity and store it $originalEntity = ...; $this->repository->save($originalEntity); // Now load it from the database $entityFromDatabase = $this->repository->getById($originalEntity->entityId()); // Compare it to the entity you created for this test self::assertEquals($originalEntity, $entityFromDatabase); } State changes, child entities, etc.

Usually an entity doesn't get persisted once. You'll be modifying it, persisting it again, adding child entities to it, removing them again, etc. So, for every situation like this, I like to write another test method, showing that all this really works, e.g.

public function it_can_save_child_entities(): void { // Create a basic version of the entity and store it $originalEntity = ...; // Add some child entity $originalEntity->addChildEntity(...); $this->repository->save($originalEntity); // Now load it from the database $entityFromDatabase = $this->repository->getById($originalEntity->entityId()); // Compare it to the entity as we've set it up for this test self::assertEquals($originalEntity, $entityFromDatabase); }

Sometimes it makes sense to add intermediate save() and getById() calls, e.g.

public function it_can_save_child_entities(): void { // Create a basic version of the entity and store it $originalEntity = ...; $this->repository->save($originalEntity); // Load and save again, now with an added child entity $originalEntity = $this->repository->getById($originalEntity->ent

Truncated by Planet PHP, read more at the original (another 3736 bytes)

Categories: Web Technologies

Tweet Only Links - Chris Shiflett

Mon, 10/01/2018 - 11:45

I’m going to try an experiment. Starting today, I’m making a commitment to tweet only links.

Why? I’ve been blogging for more than 15 years, but I blogged far more in the first 5 years than in the 10 years since. While there are many factors, I think joining Twitter drove the decline of my blogging habit more than anything else. Now, if I have something to share, I’ll write a sentence or two on Twitter and be done. Twitter lets me scratch the itch.

If I have something to share going forward, my hope is that this commitment will compel me to blog about it. If I can’t take the time to explore a thought by blogging, I should link to someone else who has. Twitter can still be great for spreading ideas, but it’s not a particularly good home for them.

In order to make this commitment more palatable (to hopefully inspire others to join me), there are a few exceptions:

  • Personal tweets are still allowed. This includes most replies. Some judgment is required, but if it’s not something you would ever consider blogging about, then it’s probably trivial enough for Twitter. I like to wish friends a happy birthday, for example.
  • Retweets are discouraged, but still allowed. I personally turned off all retweets, but retweeting doesn’t violate the spirit, since it’s similar to linking to someone else. Just be mindful not to spread the sort of shallow tweets that you’re trying to avoid yourself.
  • When you tweet a link, you can add some commentary.

If you have something to share, don’t give yourself the easy out and temporary relief that comes from a tweet. Let your desire to share lead to a blog post. It’ll be good for you.

I mentioned this idea to Chad this morning, and he committed to joining me. I hope you’ll join us, too.

Categories: Web Technologies

Surface Book 2 Nvidia card not recognized - Stefan Koopmanschap

Fri, 09/28/2018 - 05:08

So I love my Surface Book 2. It is an amazing laptop and tablet hybrid. There's very little issues I have with it. But since a couple of weeks I keep having issues with the video card. The Surface Book 2 has 2 video cards: an Intel UHD 620 card for the tablet, and an Nvidia GeForce GTX 1050 when the Surface is connected to the keyboard section for stunning graphics. Especially when playing games I recently have a very low FPS, and I had no idea what could be causing it.

When I opened my device manager, I was shocked to see that the Nvidia card was not there. I started searching the Internet and apparently, this is an issue that has been plaguing more Surface Book users. Eventually I found a solution as posted by Philip Aaron that worked for me!

  1. Open the device manager so you can see which display adapters Windows sees
  2. Disconnect power from the laptop
  3. Detach the Surface from the keyboard base
  4. Wait until the device manager has reloaded its devices
  5. Attach the Surface back to the keyboard base
  6. Wait until the device manager has reloaded its devices
  7. Now the Nvidia card should be recognized again, connect the power again

Having to do this every time I start the computer is rather annoying, so I've contacted Microsoft to see if there is a permanent solution, but for now, this at least solves my FPS issues.

Categories: Web Technologies

PHP 7.3.0RC2 Released - PHP: Hypertext Preprocessor

Thu, 09/27/2018 - 17:00
The PHP team is glad to announce the next PHP 7.3.0 pre-release, PHP 7.3.0RC2. The rough outline of the PHP 7.3 release cycle is specified in the PHP Wiki. For source downloads of PHP 7.3.0RC2 please visit the download page. Windows sources and binaries can be found on windows.php.net/qa/. Please carefully test this version and report any issues found in the bug reporting system. THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION! For more information on the new features and other changes, you can read the NEWS file, or the UPGRADING file for a complete list of upgrading notes. Internal changes are listed in the UPGRADING.INTERNALS file. These files can also be found in the release archive. The next release would be RC3, planned for October 11th. The signatures for the release can be found in the manifest or on the QA site. Thank you for helping us make PHP better.
Categories: Web Technologies

Laravel: Validate GET parameters - Christian Weiske

Tue, 09/25/2018 - 13:20

In one of our Laravel 5.6 applications at work I had to validate the data of an incoming POST request to our API.

Validation of POST data is easily done with custom Request classes that provide their validation checks via the rules() method.

A different issue are GET parameters that we got via our route definition, because the Request objects only validate POST data.

My solution was to manually add the relevant GET parameters to array-of-data-to-validate by overwriting the all() method:

app/Http/Requests/SomethingWithAType.php /** * Inject GET parameter "type" into validation data * * @param array $keys Properties to only return * * @return array */ public function all($keys = null) { $data = parent::all($keys); $data['type'] = $this->route('type'); return $data; }
Categories: Web Technologies

Laravel Passport: Ignore login errors - Christian Weiske

Tue, 09/25/2018 - 13:03

At work we built a web application consisting of one backend that provides an API for user management and login via OAuth2, and a couple of frontend applications that all rely on that API.

For OAuth2, we used the Laravel 5.6 Passport library that brings all the OAuth2 server stuff we needed.

One issue we had were exceptions that occured in the API and were logged in our own Sentry instance: One entry for every user that mis-typed his password:

League\OAuth2\Server\Exception\OAuthServerException

The user credentials were incorrect.

To solve this issue, we added the following code to our API application's exception handler:

app/Exceptions/Handler.php /** * Determine if the exception is in the "do not report" list. * * @param Exception $e Exception to check * * @return bool */ protected function shouldntReport(Exception $e) { if ($e instanceof \League\OAuth2\Server\Exception\OAuthServerException) { //6: The user credentials were incorrect return $e->getCode() == 6; } return parent::shouldntReport($e); }
Categories: Web Technologies

302 Found - Evert Pot

Tue, 09/25/2018 - 08:00

302 Found is another misunderstood status code. The intent of this status is to tell the client that the resource they tried to access is temporarily hosted somewhere else.

Because the change is temporary, the client shouldn’t update its own links to the new location but keep hitting the endpoint that sent the 302 in case something changed.

The 302 is misused in two ways. Like 301 Moved Permanently, the original intent of the specification was if a client hits a url and sees the 302, it should repeat the exact same request on the new location.

Browsers don’t do this, and tend to convert POST requests to GET. As a result, the specifications now state that you no longer can count on clients to do the same request on the Location target, and 307 Temporary Redirect was introduced. 307 requires the client to do use the same HTTP method.

The ‘incorrect’ usages is so widespread it makes more sense to consider this implicitly the ‘standard’.

Many HTTP / Web frameworks will actually now default to 302 for redirects after a POST request. The meaning frameworks intent to the client is:

“The POST request succeeded, now redirect the browser to this new location to see the result.”

It’s a valid use-case, but there is actually a different HTTP status that was specifically intended to fulfill this use-case: 303 See Other, which is actually supported by every browser.

References
Categories: Web Technologies

Test-driving repository classes - Part 1: Queries - Matthias Noback

Tue, 09/25/2018 - 00:25

There's something I've only been doing since a year or so, and I've come to like it a lot. My previous testing experiences were mostly at the level of unit tests or functional/system tests. What was left out of the equation was integration tests. The perfect example of which is a test that proves that your custom repository class works well with the type of database that you use for the project, and possibly the ORM or database abstraction library you use to talk with that database. A test for a repository can't be a unit test; that wouldn't make sense. You'd leave a lot of assumptions untested. So, no mocking is allowed.

But how do you test everything that is going on in a repository? Well, I found out a nice way of doing so, one that even allows you to use some kind of test-driven approach. In this article I'll cover one of the two main use cases for repositories: querying the database, and returning some objects for it. The other use case - storing and loading objects - will be discussed in another article.

What's a query?

In essence, a query defines criteria for selecting certain records from the database. Comparing it to the real-world equivalent: you'd have some kind of room full of stuff and you let a robot go in with a list of selection criteria. It examines things one by one to see if it matches those criteria, and if it does, it takes the thing with it, and brings it to you. How can you verify that the robot works well? Sure, you put some things in that room that match the criteria, and see if it fetches those things for you. However, you should also try dropping some things in the room that wouldn't match the criteria you gave to the robot, and verify that the robot doesn't take those things too.

For repository classes it should work the same way. Testing if some query in the repository class works, means that you should load some fixtures for records that would match the criteria. But you shouldn't forget to add some records that wouldn't match the criteria too. Otherwise, you wouldn't notice the difference between your elaborate SELECT query and a SELECT * WHERE 1 query. So basically you'd have to come up with examples, as well as counter-examples. It turns out that these counter-examples can be used to test-drive the query itself.

As an example, consider you need a query that will return a list of products, but only those which are active. You'd start with the simplest situation; a single product that should be returned:

INSERT INTO products (product_id) VALUES (1);

You then write the query for this:

$result = $this->connection ->createQuery() ->from('products') ->select('*') ->execute() ->fetchAll();

In your test you can then verify that this query indeed loads this one product. At this point I often add another record to the database, to prove that the query is capable of returning more than one object (i.e. there's no "limit" in place or anything).

INSERT INTO products (product_id) VALUES (1); INSERT INTO products (product_id) VALUES (2); Implement the first requirement

The query we wrote doesn't yet take the "is active" flag for products into consideration. So now, before you dive in and modify the query, you need to show that the code as it is doesn't yet implement all the requirements. So you add a counter-example; an inactive product:

- Active products INSERT INTO products (product_id, is_active) VALUES (1, 1); INSERT INTO products (product_id, is_active) VALUES (2, 1); - Inactive product - should be ignored INSERT INTO products (product_id, is_active) VALUES (3, 0); A failing test

If you run the test again, it will fail, because it returns an extra product that wasn't expected to be there. This is the traditional "red" phase of TDD.

You then modify the query, adding a "where" clause that will exclude inactive products:

$result = $this->connection // ... ->andWhere('active = 1') // ... ->fetchAll();

Run the test again, and the light will be green again.

Green; implement another requirement

Now you can continue working on the next requirement. In this example, we need the product to be in a group of products that's marked as "stock" products. With every extra requirement, we run into another variation we'd need to check. Consider a product that is active, but is not in the righ

Truncated by Planet PHP, read more at the original (another 4610 bytes)

Categories: Web Technologies

301 Moved Permanently - Evert Pot

Tue, 09/18/2018 - 08:00

301 Moved Permanently tells a client that the resource they’re trying to access has moved to a new location. The server will include the new location in the Location header.

When a client sees this response, it should repeat the same request on the new location, and if it can, it should also update any links it may have had to the old location and update it to the new one.

Example HTTP/1.1 301 Moved Permanently Server: Curveball/0.4.2 Location: https://evertpot.com/http/301-moved-permanently Real-world Usage

According to the specifications, a client should repeat the exact same request on the new location. In practice, a lot of clients don’t do this.

The reality is that when many clients do something like a POST request on a resource that responds with a 301, almost every client will assume that the POST was successful and do a GET request on the new resource for additional information, including browsers.

This incorrect behavior was so common, that when the HTTP specifications were updated, the newer documents mention this behavior. In addition, a new status-code was introduced later that restored the original behavior: 308 Permanent Redirect.

References
Categories: Web Technologies

Assertions and assertion libraries - Matthias Noback

Mon, 09/17/2018 - 23:55

When you're looking at a function (an actual function or a method), you can usually identify several blocks of code in there. There are pre-conditions, there's the function body, and there may be post-conditions. The pre-conditions are there to verify that the function can safely proceed to do its real job. Post-conditions may be there to verify that you're going to give something back to the caller that will make sense to them.

In a quasi-mathematical way: most pre-conditions verify that the input is within the supported domain of the function. Post-conditions verify that the output is within the range of the function. A mathematical function (as far as I know) only verifies its pre-conditions, because bad input could've been provided for which the function just doesn't work (e.g. 1/x doesn't work for input x = 0). Once the input has been validated, the function will yield an answer which doesn't have to be verified. Every answer will be valid no matter what.

It works the same way for function pre-conditions and post-conditions in code; you'll usually only find pre-conditions in code, no post-conditions. Quite often however you may not even find pre-conditions, but "medio-conditions"; that's when input validation happens everywhere inside the function.

This is not a desirable situation: for the function body to be as clear as possible, we'd want to push all pre-condition checks to the top of the function. Then we'll end up with a function body where "nothing can go wrong".

Sometimes the programming language itself can help with these pre-conditions: for instance, the language may support strict typing, which prevents certain types of invalid input to be provided. Some languages offer more advanced ways of defining pre-conditions, like pattern matching.

PHP doesn't have a lot of options, and before PHP 7 we didn't even have a way to define parameter types using primitives like int, string, etc. So many of us have been doing manual assertions at the top of functions, to verify some basic aspects of the provided arguments, like this:

if (!is_string($name)) { throw new InvalidArgumentException('$name should be a string'); }

This leads to lots of code duplication, across projects even, so it's a great opportunity for code reuse. Benjamin Eberlei created a popular library for it, and Bernhard Schussek created a variation on it. Both have become quite commonly used in projects. They offer useful shortcuts like Assert::string($value), Assert::greaterThan($value), which will check the value and throw an InvalidArgumentException if an expectation is not met. You can provide custom exception messages as well:

Assertion::string($name, '$name should be a string');

The funny thing is, PHP already has a built-in assertion tool. It's not as convenient as the assertion functions that these libraries provide. You'd have to write all the checks yourself:

assert(is_string($name), '$name should be a string');

On the other hand, it has one interesting feature that exposes the core idea of assertions: the fact that you can turn them off (e.g. in a production environment), without touching the code. Even though you can't easily turn off an assertion library once you start using it, I still think it's a very interesting test to see if you're using such a library in the correct way: just entertain the thought that you would turn the assertions off, would the system still function correctly?

I think this deserves a bit of an explanation. We should first consider the question why we need assertions in the first place. The answer is that some callers may provide bad data as input arguments to our function, so we need to protect it against this bad data. We throw an exception because things aren't going to work out well if we'd just carry on. The culprit however, isn't the innocent user of our program, it's the caller of the function. So we'd never want an InvalidArgumentException to bubble up to the user.

So the first rule of using assertions is: don't use assertions to validate user input, use it to validate function arguments. This means that, given that the user uses the application in a way that is valid and supported by our user interface (e.g. they are not trying to "hack" our system by tampering with POST request data), they should never receive a useless "500 Internal server error" response because some assertion failed. The other way around: if you find an as

Truncated by Planet PHP, read more at the original (another 7775 bytes)

Categories: Web Technologies

Pages