emGee Software Solutions Custom Database Applications

Share this

Planet PHP

People blogging about PHP
Updated: 4 hours 30 min ago

When I started writing PHP... - larry@garfieldtech.com

Tue, 02/12/2019 - 17:46
When I started writing PHP...

I don't know exactly when I started writing PHP. It was shortly after the start of my second quarter of my freshman year of college, when a newly-met friend of mine introduced me to PHP as an easier to understand alternative to Perl. That puts it, I think, somewhere in January or February of 1999.

20 years ago, give or take a week. I have been writing PHP for two decades. That's more than half my lifetime. I feel old.

I thought it would be amusing (mostly at my expense) to look back a bit on just how much the PHP world has changed in the last two decades.

Larry 12 February 2019 - 7:46pm
Categories: Web Technologies

411 Length Required - Evert Pot

Tue, 02/12/2019 - 07:00

Most HTTP requests that have a request body, will also have a Content-Length header indicating how big the body will be. However, this is optional for some cases, such as when Chunked Transfer Coding is used.

It’s useful for a client to not include a Content-Length header for a few different cases. For instance, a client might send a HTTP request body based on a stream.

If a server does not support this feature, it can indicate this by sending back 411 Length Required.

In a situation like this, a recourse a client might have is to buffer the entire request to determine the real length.

Example HTTP/1.1 411 Length Required Content-Type: text/html Server: curveball/0.6.0 <h1>This server requires a Content-Length</h1> References
Categories: Web Technologies

PHP 7.3.2 Release Announcement - PHP: Hypertext Preprocessor

Wed, 02/06/2019 - 16:00
The PHP development team announces the immediate availability of PHP 7.3.2. This is a bugfix release, with several bug fixes included.All PHP 7.3 users are encouraged to upgrade to this version.For source downloads of PHP 7.3.2 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.2.15 Released - PHP: Hypertext Preprocessor

Wed, 02/06/2019 - 16:00
The PHP development team announces the immediate availability of PHP 7.2.15. This is a bugfix release.All PHP 7.2 users are encouraged to upgrade to this version.For source downloads of PHP 7.2.15 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

410 Gone - Evert Pot

Tue, 02/05/2019 - 07:00

410 Gone is a status code that can be used in cases where a resource is gone and never coming back. It’s a more specific version of 404 Not Found.

A good example for using 410 instead of 404 is when a resource was intentionally removed.

Using 410 can be helpful, because it signals to other people linking to you that the link is dead and should be removed. A 404 is the default for missing resources, and it can just mean that the owner of the site has moved the content and didn’t put the right redirects in place.

So to sum it up: 410 implies intent.

Example HTTP/1.1 410 Gone Content-Type: text/plain Server: curveball/0.6.0 I deleted it and it's never coming back! References
Categories: Web Technologies

DDD Europe notes - Day 2 - Matthias Noback

Fri, 02/01/2019 - 03:50
Cyrille Martraire: Domain modeling towards First Principles

This was a talk from the first day, but it required some more processing before writing about it. Cyrille is one of my favorite speakers. He's fast, funny and brings a lot of interesting topics to the table. So many that it's sometimes hard to keep following his train of thought, and writing down some notes at the same time.

A central concept from his talk was what he called the waterline between IT and the business. In a traditional scenario, developers get provided with "work" on a case-by-case basis. They don't learn about the general idea or plan, or even the vision, goal or need that's behind the "work item". They just have to "implement" it. It leads to badly designed code. But it also leads to the wrong solutions being delivered. If only developers could have talked with the people who actually have the problem for which they build the solution. Maybe there's another problem behind it, or maybe the business has provided the developer with a solution, instead of a problem. To higher the waterline means to get more involved with the customers and users, to understand their problems, and work together on a solution. Make sure you get involved.

When looking for the right solutions, investige the problems and use the following heuristic: "Consider the intensional alternative". Cyrille considers "intensional" a pedantic word and likes it. It's opposed to "extensional". Extensional corresponds to enumarating the results. Intensional means defining the predicate which will produce those results. Looking for intensional solutions means you'll end up with a better understanding of the problem. And also an automatable one.

While collecting these intensional aspects of existing business problems, as a developer you will be building a theory about that business. Cyrille warns against the illusion that a domain is simply a lot of information withs if-s on top. Business is messy, so we shoudn't be obsessed with rules. Some parts of a domain allow theorizing, some don't.

This nicely aligns with my own experience, trying to understand a business domain. Domain experts often aren't aware of the inconsistencies, or impossible rules they come up with. Once you bring in some logic, some rules seem reasonable but just aren't feasible. These may be areas where there's manual intervention in an otherwise automated system.

Another interesting concept Cyrille brought up was that of "skeuomorphism". He noticed that software solutions seem to continue building on technology from the past. Software systems often look like they're rebuilding a paper bureaucracy, but now it's digital. You can't really be "disruptive" if you don't think about radically different ways of solving some problem for the user. This was a bit of shock, because I realized that I often use "paper metaphors" to find out a possible solution for a design issue. Then again, maybe there's room for both - a paper metaphor as a design tool, yet a non-paper bureaucracy inspired software solution.

Maaret Pyhäjärvi: Breaking Illusions with Testing

Identifying herself as a "feedback fairy", Maaret talks about testing, in a very broad sense. It doesn't only cover automated testing, but also exploratory testing, and what you're doing with them. Tests don't break code, they break the illusions you have about it. The way Maaret explained testing, I immediately became scared of all the illusions I have about my code and that I should start breaking them.

I like how Maaret used the term "heuristics", like more DDD-ers do, to share with us how she and other testers do their work. It seems it's very common to share heuristics in the testing community. Very interesting! I don't think programmers share them as freely as they should.

Testing an application starts with realizing: you don't know much. So you have to create some sort of a map of what's there (functions, data, the platform, etc.). Start to discover, and never be bored. Always look for the interesting things, and "poke it until it pops".

In general, what you'll find is all kinds of illusions (they could be called "assumptions", I think). In testing an application ("it has high code coverage, so it's tested") but also in the general activity of developing software ("if we have this new feature, we'll earn more money").

Thinking in terms of illusions, I think most development teams are very good at them. We have all kinds of ideas about our code, our way of working, the application, our teammates, the company, etc. But they aren't really tested. It'll be smart to challenge them.

Also, looking at how others approach their problems is very useful. There will be a different perspective that you

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

Categories: Web Technologies

Blast from the Past - thePHP.cc

Thu, 01/31/2019 - 23:00
Categories: Web Technologies

DDD Europe notes - Day 1 - Matthias Noback

Thu, 01/31/2019 - 11:00
Eric Evans: Keynote ("Language in Context")

Starting out with the basics (words have meaning within a context; when we make the boundary of this context explicit we end up with a bounded context), Eric discussed two main topics: the Big Ball of Mud, and bounded contexts in the context (no pun intended) of microservices.

Legacy applications are always framed in a negative way, as if it's something to get away from. Personally, I've come to enjoy them a lot. However, there will always be the urge to work around legacy code. The Bubble Context (PDF) can be a great way of creating a new model that works well next to the already existing models. To keep a safe buffer between the new and the old model, you could build an Anti-Corruption Layer (ACL). A fun thing Eric mentioned is that the buffer works in two directions. The ACL also allows the old model to keep functioning without being disturbed by all the new things that are going on in the Bubble Context.

Given that a bounded context may or may not align with an actual subdomain, it may very well be that a legacy context is actually a Big Ball of Mud, with unified models, and simply just a lot of domain knowledge written between the many spaghetti lines that are in there. However, even though it is a mess, and it's getting harder to work with it every day, it may still be what you could call a "Mature Productive Context". The question is: is it still aligned with business views? If it is, we could improve at least maintainability and the cost of change by performing local refactorings. If it isn't, it'll be very hard to change anything. If the basic assumptions of the model change, rework will be very costly.

As a matter of fact, for a project I'm currently working on, we're looking into a module (or context), which requires some heavy refactoring, because it has become technically very hard to work with it. However, the business is still quite happy about it, and it's quite central to its processes.

An important Domain-Driven approach which can be used in the area of legacy code is where you analyze the different subdomains, and find out which ones are generic, and which ones are "core" to the business. As an example, in the aforementioned project there are actually two candidates for context-level improvements. One is related to Sales (which is the heart of this financial application), and one is related to Addressbook records (which is very much supportive to the Sales part). One could say it's even generic, in the sense that an off the shelf solution might be preferable. We wouldn't want to spend a lot of design or development effort there either.

Eric mentioned the term "Quaint Context" as a suitable name for a context that one would consider "legacy". It uses outdated technology probably, and has become hard to maintain. It won't be possible to make big changes there (as mentioned, because these basic assumptions can't easily be changed), so another good name could be "Patch-by-Patch Context".

With a microservice architecture, another option to deal with legacy contexts becomes what Eric calls the "Exposed Legacy Asset" (yet another nice term!). This will be a legacy application which starts to adapt to the microservices environment by producing messages that will be useful for actual microservices in that environment. For instance, database triggers could be used to produce events. The external events themselves don't have to be as low-level as the internal events that caused them.

Eric touches on several other interesting aspects of microservice architecture, but I wanted to briefly mention some other relevant ideas here. Eric looked back at 15 years of Domain-Driven Design and proposed that by now we maybe need a definition of DDD itself. He doesn't want DDD to be just a club, but asks for intellectual honesty. If you try to apply DDD and somehow it fails, you should share this story. If you're skeptical about some aspect of DDD, talk about it. I like how it boils down to focusing on the core domain, exploring models together, and speaking a ubiquitous language in an explicitly bounded context. Nice!

Rebecca Wirfs-Brock: Growing Your Design Heuristics Toolkit

This one was a workshop with limited access, so I was lucky I could attend it. Rebecca had spoken in a previous edition of the conference about heuristics, which triggered my interest in the idea. The workshop was about the process behind it. It had some interesting pointers, like a PDF about the concept and a book by Billy Vaughn Koen: Discussion of the Method. Definitely things to check ou

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

Categories: Web Technologies

Using img2lambda to publish your Serverless PHP layer - Rob Allen

Thu, 01/31/2019 - 03:02

This interesting tweet by Clare Liguori came to my attention last week:

This new img2lambda tool will take the layers of a Docker container and convert them to AWS layers for use in Lambda.

I poked around with Clare's example and updated my lambda-php project in order to understand how it works. I also rewrote my runtime's bootstrap to make it clearer.

The clever thing from my point of view is that you can build your PHP runtime layer locally using Docker and then publish the layers to AWS for use in your Lambda functions. This means you can now use the layer in different projects and have them all reference the same PHP runtime.

The magic of Docker

This is all done with the magic of Docker. Specifically, we create a Dockerfile that creates to containers:

  • A container to build the PHP binary
  • A container containing the layers that img2lambda will upload to AWS

Simplified, it looks like this:

# Build PHP in the Lambda container FROM amazonlinux:2017.03.1.20170812 as builder # PHP version of create ARG ver="7.3.1" RUN sed -i 's;^releasever.*;releasever=2017.03;;' /etc/yum.conf && \ yum clean all && \ yum install -y autoconf bison gcc gcc-c++ make libcurl-devel {etc} RUN curl -sL https://github.com/php/php-src/archive/php-${ver}.tar.gz | tar -xvz && \ cd php-src-php-${ver} && \ ./buildconf --force && \ ./configure --prefix=/opt/php/ --with-openssl --with-curl --{etc} && \ make install && \ /opt/php/bin/php -v # copy php binary into /runtime/bin/php RUN mkdir -p /runtime/bin && \ cp /opt/php/bin/php /runtime/bin/php # copy bootstrap files into /runtime COPY src/* /runtime/ # Create runtime container for use with img2lambda FROM lambci/lambda:provided as runtime COPY --from=builder /runtime /opt/

The first part download and compiles the PHP binary and puts it into /runtime/bin/php and also copies in the bootstrap files required to make the layer act as a Lambda runtime.

The second part simply copies all the files in /runtime in the first container into a new container. This new container containers a single layer which is our PHP runtime.

To build it we do:

$ docker build -t lambda-php-runtime .

The tag name can be anything.

Create the the layer in AWS

To create the AWS layer we use img2lambda:

$ img2lambda -i lambda-php-runtime:latest -r eu-west-2 -n lambda-php73

This tool will find the layer in the runtime container and upload it to eu-west2 and then store the identifier in output/layers.json which looks like this.

[ "arn:aws:lambda:eu-west-2:66...06:layer:lambda-php73-sha256-e3c4...2e618b:1" ]

Using in Serverless Framework

You can take the ARN number and use it for your actions in serverless.yml like this:

functions: hello: handler: handler.hello layers: - "arn:aws:lambda:eu-west-2:66...06:layer:lambda-php73-sha256-e3c4...2e618b:1"

This is the way that we can re-use our PHP runtime in all our actions across multiple projects.

Serverless also allows you to import data from JSON files into your serverless.yml file, so you can also do:

functions: hello: handler: handler.hello # {file name}.{function name}. In this case: hello() in handler.php layers: ${file(../php-runtime/output/layers.json)}

This has the advantage that when you re-build and upload PHP runtime layer, your project picks it up, which could also be convenient.

Testing locally

One of the benefits of building the runtime in Docker is that we can run it locally for testing our Lambda function. As our runtime container inherits from lambci/lambda:provided, we get an environment that looks very much like Lambda itself.

To test locally, we use another container and inherits from our runtime one and copies in the PHP files for our function. The Dockerfile looks something like this:

FROM lambda-php-runtime as function COPY handler.php /var/task/src/handler.php

We create our cont

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

Categories: Web Technologies

Ketting 2.5 release. - Evert Pot

Wed, 01/30/2019 - 09:00

Ketting is an attempt at making a generic Hypermedia API client for javascript. It uses a ‘link’ and following links as the most important primitive.

Last week I released version 2.5.0 on NPM so maybe it’s time to list some of the improvements since the last update in order from most to least interesting.

JSON:API support

JSON:API is a standard for making JSON-based APIs, and it has some support for hypermedia ideas as well.

In particular, the standard has a links object, and it also defines a relationship between collections and members of collections.

This release now ships with a ‘representor’ for JSON API, which means you can now do something like this:

const myResource = await home .follow('next') // This might be a html5 document .follow('author') // This might be a HAL document .follow('about') // This might be a JSON:API document

All of these will now be seamless regardless of which format any of these hops used, only when you get() and put() the format is relevant again.

A lot of help in getting this right came from JSON:API community members such as Gabe Sullice and Ethan Resnick. If you’re interested in the full discussion about how JSON:API maps to HATEOAS read the Github issue.

go() function

Not every endpoint will have every appropriate link to another resource. Sometimes you just have to work with what you have, and fetch a resource yourself.

The go() function is a function that exists on a resource and simply gives you a new resource based on the url you passed. The url can be relative and will be resolved based on the ‘current’ resource.

const anotherResource = resource.go('?q=hello'); Resource is generic

If you use typescript with this package, it might be desirable to have some typing.

Adding good support for this will be an ongoing process, but as a first step the Resource class is now generic.

This means that you can define a function such as:

function foo(): Resource<MyBodyType> { // ... }

Typescript will then use MyBodyType as the type that will be returned from get() and refresh() and will demand that the value passed to put() has this type.

By default this is any.

I think this is a decent first step, but I also imagine this will have to continue to evolve.

esModuleInterop is false

The Typescript build now has esModuleInterop off. Apparently keeping it set to true caused anyone who uses the library and has this setting set to false to get errors.

So in order to not force people to change this setting, esModuleInterop is now off, which means the library will work regardless of your own preference.

Categories: Web Technologies

409 Conflict - Evert Pot

Tue, 01/29/2019 - 07:00

409 Conflict is used in cases where the HTTP request was valid, but the current state of the server prevents it from being executed.

This is usefor for API’s. A few hypothetical examples:

  1. A user wants to add a file to a folder, but the folder doesn’t exist yet.
  2. Amazon S3 uses it when you try to delete a bucket that’s not empty.
  3. You’re creating a new blog post, but it refers to a category that was deleted.

The key here is that it might be possible to run the same request again after this conflict is resolved, by for example:

  1. Creating the folder you’re trying to upload to.
  2. Removing all items from the S3 bucket before removing it.
  3. Re-creating or undeleting the category you’re trying to assign to the blog post.

The HTTP specification recommends that the HTTP response body contains information in the response body that the client or user can use to resolve the conflict.

Example HTTP/1.1 409 Conflict Content-Type: text/plain You tried to upload a file to a folder that doesn't exist. Create the folder and try again! Usage

If you are building an API, it’s a good idea to emit 409 conflict for these situations. It can be seen as a more specific code than 400 and somtimes 409.

You might even be able to define a response body that a client can use to automatically resolve the conflict, or at least inform the user in a standard way what was wrong.

Categories: Web Technologies

Who pays for PHP? - thePHP.cc

Thu, 01/24/2019 - 23:00
Categories: Web Technologies

Registering Module-Specific Routes in Expressive - Matthew Weier O'Phinney

Thu, 01/24/2019 - 09:30

In Expressive, we have standardized on a file named config/routes.php to contain all your route registrations. A typical file might look something like this:

declare(strict_types=1); use Zend\Expressive\Csrf\CsrfMiddleware; use Zend\Expressive\Session\SessionMiddleware; return function ( \Zend\Expressive\Application $app, \Zend\Expressive\MiddlewareFactory $factory, \Psr\Container\ContainerInterface $container ) : void { $app->get('/', App\HomePageHandler::class, 'home'); $app->get('/contact', [ SessionMiddleware::class, CsrfMiddleware::class, App\Contact\ContactPageHandler::class ], 'contact'); $app->post('/contact', [ SessionMiddleware::class, CsrfMiddleware::class, App\Contact\ProcessContactRequestHandler::class ]); $app->get( '/contact/thank-you', App\Contact\ThankYouHandler::class, 'contact.done' ); $app->get( '/blog[/]', App\Blog\Handler\LandingPageHandler::class, 'blog' ); $app->get('/blog/{id:[^/]+\.html', [ SessionMiddleware::class, CsrfMiddleware::class, App\Blog\Handler\BlogPostHandler::class, ], 'blog.post'); $app->post('/blog/comment/{id:[^/]+\.html', [ SessionMiddleware::class, CsrfMiddleware::class, App\Blog\Handler\ProcessBlogCommentHandler::class, ], 'blog.comment'); }

and so on.

These files can get really long, and organizing them becomes imperative.

Using Delegator Factories

One way we have recommended to make these files simpler is to use delegator factories registered with the Zend\Expressive\Application class to add routes. That looks something like this:

namespace App\Blog; use Psr\Container\ContainerInterface; use Zend\Expressive\Application; use Zend\Expressive\Csrf\CsrfMiddleware; use Zend\Expressive\Session\SessionMiddleware; class RoutesDelegator { public function __invoke( ContainerInterface $container, string $serviceName, callable $callback ) : Application { /** @var Application $app */ $app = $callback(); $app->get( '/blog[/]', App\Blog\Handler\LandingPageHandler::class, 'blog' ); $app->get('/blog/{id:[^/]+\.html', [ SessionMiddleware::class, CsrfMiddleware::class, Handler\BlogPostHandler::class, ], 'blog.post'); $app->post('/blog/comment/{id:[^/]+\.html', [ SessionMiddleware::class, CsrfMiddleware::class, Handler\ProcessBlogCommentHandler::class, ], 'blog.comment'); return $app; } }

You would then register this as a delegator factory somewhere in your configuration:

use App\Blog\RoutesDelegator; use Zend\Expressive\Application; return [ 'dependencies' => [ 'delegators' => [ Application::class => [ RoutesDelegator::class, ], ], ], ];

Delegator factories run after the service has been created for the first time, but before it has been returned by the container. They allow you to interact with the service before it's returned; you can configure it futher, add listeners, use it to configure other services, or even use them to replace the instance with an alternative. In this example, we're opting to configure the Application class further by registering routes with it.

We've even written this approach up in our documentation.

So far, so good. But it means discovering where routes are registered becomes more difficult. You now have to look in each of:

  • config/routes.php
  • Each file in config/autoload/:
    • looking for delegators attached to the Application class,
    • and then checking those to see if they register routes.
  • In config/config.php to identify ConfigProvider classes, and then:
    • looking for delegators attached to the Application class,
    • and then checking those to see if they register routes.

The larger your application gets, the more work this becomes. Your config/routes.php becomes way more readable, but it becomes far harder to find all your routes.

One-off Functions

In examining this problem for the upteenth time this week, I stumbled upon a solut

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

Categories: Web Technologies

bigint-money: an NPM package for doing currency math - Evert Pot

Wed, 01/23/2019 - 10:22

Not long ago, I was confused about doing math with money and floating point issues. After a bunch of research and help from friends I figured out what many already did before me: Using floating points is indeed bad. You can get rounding issues and really want to use ‘precise math’.

After that, I realized I wanted to use the new Ecmascript bigint type as a basis for representing money. This is supported by recent versions of Node.js and Typescript, which is where I need it.

There’s a problem though, the bigint type only holds ‘whole numbers’ and doesn’t do fixed-point decimal-math. I looked around on NPM for something that would abstract this for me, but couldn’t find a library.

So I spent a couple of days writing a simple npm library called bigint-money that wraps the bigint type. It’s written in Typescript and open-source so it’s here for anyone to use: https://www.npmjs.com/package/bigint-money.

Major features:


Most ‘money’ libraries on NPM only use 2 digits for precision, or use Javacript’s “number” and will quickly overflow.

The only comparible library I found was big-money. It’s probably the best alternative if your Javascript environment doesn’t have support for bigint yet.

My simple benchmark calculates a ledger with 1 million entries.

bigint-money | big-money ledger 816 ms | 43.201 ms % 100 % | 5294 %

The benchmark script can be found in the repository.

I want to stress though that I can’t take credit for this (pretty good) result. The library is fast because bigint is fast.

I did need to implement a few functions myself, and I actually feel that somebody who’s better at writing fast code could probably do a much better job than I did.

I imagine that specifically the moneyValueToBigInt and bigintToFixed intenral functions could probably be optimized by someone much smarter than me.


This is how it generally works:

// Creating a money object. import Money from 'bigint-money'; const foo = new Money('5', 'USD');

It’s possible to create a new money object with a Number as well

const foo = new Money(5, 'USD');

However, if you pass it a number that’s ‘unsafe’ such as a float, an error will be thrown:

const foo = new Money(.5, 'USD'); // Unsa

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

Categories: Web Technologies

408 Request Timeout - Evert Pot

Tue, 01/22/2019 - 04:00

If a client is too slow to send a full HTTP request, a server can send back a 408 Request Timeout error response.

A request coming in too slow can happen for a variety of reasons, including slow internet connections, completely lost internet connections or bad actors.

When a server sends back the 408, it no longer wants to wait for the request and kills the connection.

A robust client might try to repeat the request as soon as they receive this response.

Example HTTP/1.1 408 Request Timeout Connection: close Content-Type: text/plain Too slow! Try again References
Categories: Web Technologies

Creating a custom magic file database - Christian Weiske

Thu, 01/17/2019 - 12:35

The unix file utility command uses a "magic" database to determine which type of data a file contains, independently of the file's name or extension.

Here is how I created a custom magic database for testing purposes:

Test files

At first I created some files to run the tests on:

test.html test.php <?php echo 'foo'; ?> test.23 Test 23

Let's see what the standard magic database detects here:

$ file test.* test.23: ASCII text test.foo: PHP script, ASCII text test.html: html document, ASCII text $ file -i test.* test.23: text/plain; charset=us-ascii test.foo: text/x-php; charset=us-ascii test.html: text/html; charset=us-ascii Magic database

The magic database contains the rules that are used to detect the type.

It's a plain text file with a rule on each line. Lines may refer to the previous line, so that rules can be combined. The full documentation is available in the magic man page.

Here is my simple file that detects "23" within the first 16 bytes of the file and returns the "text/x-23" MIME type:

my-magic 0 search/16 23 File containing "23" !:mime text/x-23

We can already use it:

$ file -m my-magic test.23 test.23: File containing "23", ASCII text Compilation

If you want to use it many times, you should compile it to a binary file for speed reasons:

$ file -C -m my-magic $ file -m my-magic.mgc test.* test.23: File containing "23", ASCII text test.foo: ASCII text test.html: ASCII text $ file -i -m my-magic.mgc test.* test.23: text/x-23; charset=us-ascii test.foo: text/plain; charset=us-ascii test.html: text/plain; charset=us-ascii

The html and PHP files that have been detected properly earlier are not detected anymore, because my own magic database does not contain the rules of the standard magic file (/usr/share/misc/magic.mgc).

You may however pass multiple magic files to use, separated with a :

$ file -i -m my-magic.mgc:/usr/share/misc/magic.mgc test.* test.23: text/x-23; charset=us-ascii test.foo: text/x-php; charset=us-ascii test.html: text/html; charset=us-ascii Programming language detection

With this knowledge, I wrote a magic file that detects the programming language in source code files, so that phorkie can automatically choose the correct file extension: MIME_Type_PlainDetect.

Categories: Web Technologies

Some changes for me - Stefan Koopmanschap

Thu, 01/17/2019 - 08:00

For the past years a lot of my focus has been on the (PHP) community. I've spoken at numerous conferences and usergroups. And although I've been cutting down on the amount of conferences, I've done more usergroups in the past year than in the years before that.

In December 2018, I've made a decision to cut down on this a bit more. This has nothing to do with not wanting to speak anymore, but more with an opportunity that has arisen that I want to take. I want to put 110% of my effort into this, which means I have to cut down on other activities that I'm doing. Speaking at usergroups and conferences is one of those things.

PHP has been my biggest hobby for the past 20+ years. It is great that I have been able to make it my job as well. Since quite a few years, I've picked up on something I've been interested in for years. I've started doing live radio. My first radio show was on the now discontinued Internet radiostation On Air Radio, after which I've moved on to another Internet radiostation IndieXL. Both times I did everything in my own little radio studio that I had built at home. It was a lot of fun.

My interest in radio already began when I was a teen. A Dutch morning show was also broadcasting on TV, so I was "watching radio" every morning. In the 90's, the Dutch radiostation KinkFM introduced me to an incredible amount of alternative music. KinkFM was the best radiostation I could imagine in terms of music, but also in terms of DJ's. People with an incredible passion for and knowledge of music. When the station was stopped by its owner in 2011, I was incredibly sad.

2 years ago one of the original founders of KinkFM saved the brand name from the company that at that time owned the name. While he wasn't planning to restart the station, the response he got was overwhelming, so he started researching his options. I got in touch and over a year ago I started doing a Spotify playlist for them called KLUB KINK.

Late last year, the announcement came: A new radiostation focussing on alternative music will be launched. Since FM is something nearly of the past, the name will now be KINK.

I have been asked to evolve my Spotify playlist into a podcast, and next to that, present a radioshow. After giving it some thought and looking at my schedule, I have decided to take this opportunity. I love doing radio, and to be able to do it for my all-time favorite radiostation is amazing. Starting on Thursday February 7, I will be doing a radioshow every Thursday from 7PM to 9PM.

Will I be completely gone from conferences and usergroups? Of course not! But as I mentioed earlier, I really want this to succeed, I want to give it 110% of my effort, and that means making tough choices.

Categories: Web Technologies

407 Proxy Authentication Required - Evert Pot

Tue, 01/15/2019 - 07:00

407 Proxy Authentication Required is an error a HTTP proxy returns if it requires authentication. It’s really similar to 401 Unauthorized.

Example HTTP/1.1 407 Proxy Authentication Required Proxy-Authenticate: Basic; realm="Secured area"

As you can see above, the response looks pretty similar to 401 and can use the same authentication schemes.

This is an example of a client authenticating with a proxy:

GET / HTTP/1.1 Proxy-Authorization: Basic d2VsbCBkb25lOllvdSBmb3VuZCB0aGUgc2Vjb25kIGVhc3RlciBlZ2cK

If a clients connects to a server that requires authentication via a proxy that also requires authentication, both headers might appear in a request:

GET / HTTP/1.1 Proxy-Authorization: Basic ZWFzdGVyIGVnZzpudW1iZXIgdGhyZWUK Authorization: Bearer c2VuZCBtZSBhIHR3ZWV0IG9yIHNvbWV0aGluZwo Usage

HTTP proxies used to be more common. They can act like local caches or provide an additional layer of security in a corporate environment. These days they are less common for those purposes. Caching is not as needed, and the security layer is more often implemented with a VPN. Most HTTP proxies these days are reverse proxies, which is mostly transparent for HTTP clients.

Basic and Digest authentication for proxies is widely supported by browsers and other HTTP clients.

Categories: Web Technologies