Category Archives: Software development

Easy to miss issue with built-in PHP server – No Apache, no .htaccess.

I had an issue where I could not get the .htaccess of a PHP project I had to work.
I couldn’t understand why simple .htaccess code was not working.
After some wasted time, the obvious came to light, I was testing the project through scripts that started the built-in PHP server. Does the PHP server handle .htaccess files? A quick Bard AI request reveals the issue,


Does the in built PHP server handle .htaccess files?


No, the built-in PHP server does not handle .htaccess files. .htaccess files are specific to the Apache web server, and the built-in PHP server is not an Apache web server.

If you need to use .htaccess files, you will need to use a real web server, such as Apache or Nginx.

There are a few workarounds for using .htaccess files with the built-in PHP server. One workaround is to create a PHP script that parses the .htaccess file and handles all routing. Another workaround is to use a real web server to serve the .htaccess file, and then use the built-in PHP server to serve the rest of your website.

However, it is generally not recommended to use the built-in PHP server in production. It is intended for development and testing purposes only.


There you go. The built-in PHP server is not an Apache web server. “use a real web server, such as Apache or Nginx.” : )

The CSP(Content Security Policy) of a page is blocking a request. How do I find out the CSP of the page using JavaScript?

When dealing with external requests, CORS errors can often occur.
CORS settings have generally become standardized to use CSP (Content Security Policy) settings.
These CSP settings can be set in multiple places, so it can be a little confusing what the final CSP is.
I asked AI (Bard), and got a useful (Bard has sometimes responded with incorrect responses) response.


The CSP(Content Security Policy) of a page is blocking a request. How do I find out the CSP of the page using JavaScript?


There are two ways to find out the CSP of a page using JavaScript:

  1. Check the HTTP response headers. This is the most reliable way to find the CSP, as it is the source of truth. To do this, you can use the document.documentURI property to get the URL of the page, and then use the XMLHttpRequest object to make a request to the URL. Once you have the response, you can check the Content-Security-Policy header to get the CSP.
  2. Check the <meta> tags. CSPs can also be specified using <meta> tags in the HTML head section. To check for a CSP in a <meta> tag, you can use the document.querySelector() method to find the <meta> tag with the http-equiv attribute set to Content-Security-Policy. If the <meta> tag is found, you can get the CSP from the content attribute.

Here is an example of how to find the CSP of a page using JavaScript:

JavaScript
function getCSP() {
  // Check the HTTP response headers.
  const xhr = new XMLHttpRequest();
  xhr.open('GET', document.documentURI);
  xhr.send();
  xhr.onload = function() {
    if (xhr.status === 200) {
      const csp = xhr.getResponseHeader('Content-Security-Policy');
      if (csp) {
        return csp;
      }
    }
  };

  // Check the <meta> tags.
  const metaTag = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
  if (metaTag) {
    return metaTag.content;
  }

  // If no CSP is found, return null.
  return null;
}

// Get the CSP of the page.
const csp = getCSP();

// Do something with the CSP, such as logging it to the console.
console.log(csp);
Use code with caution.

If the CSP of the page is blocking a request, you can try the following:

  • Whitelisting the request in the CSP. This is the most secure option, as it allows you to explicitly specify which requests are allowed. To do this, you need to add the source of the request to the CSP. For example, if the CSP is blocking a request to https://example.com/script.js, you would need to add the following to the CSP:
script-src https://example.com/
  • Using a report-only CSP. This option allows you to test changes to your CSP without blocking any requests. To do this, you need to add the report-only directive to the CSP header. For example:
Content-Security-Policy-Report-Only: script-src https://example.com/

This will cause the browser to report any violations of the CSP to the specified URI, but the requests will not be blocked.

  • Disabling the CSP. This is the least secure option, as it disables all CSP protections. To do this, you need to remove the Content-Security-Policy header from the HTTP response.

Important: Be very careful when disabling or changing a CSP, as this can make your website vulnerable to attack.


If a page has CSP both in the response headers and in one or more meta tags, how are they merged?


If a page has CSP both in the response headers and in one or more meta tags, the CSP in the response headers is used. The meta tags are ignored.

This is because the CSP in the response headers is the most authoritative source of the CSP for the page. The meta tags are only used if there is no CSP in the response headers.

This behavior is specified in the CSP specification:

If multiple policies are received for the same resource, the HTTP response header value takes precedence over the HTML meta element value.

If you need to specify a CSP for a page, it is best to do so in the response headers. This will ensure that the CSP is applied consistently, regardless of whether the page is loaded from the server or from a cache.

If you are using a meta tag to specify a CSP, be aware that it will be ignored if there is a CSP in the response headers. You should also be aware that meta tags are not supported in all browsers.


What about if multiple CSP meta tags exist?


If a page has multiple CSP meta tags, they are merged into a single CSP. The order in which the meta tags are merged is not specified in the CSP specification, so it is best to avoid using multiple meta tags to specify a CSP.

If you need to specify a CSP for a page, it is best to do so in the response headers. This will ensure that the CSP is applied consistently, regardless of whether the page is loaded from the server or from a cache.

If you are using meta tags to specify a CSP, be aware that they may be merged in an unexpected order. You should also be aware that meta tags are not supported in all browsers.

Here is an example of how multiple CSP meta tags may be merged:

HTML
<head>
  <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
  <meta http-equiv="Content-Security-Policy" content="style-src 'self'">
</head>
Use code with caution.

This would be merged into the following CSP:

script-src 'self'; style-src 'self'

The order of the directives in the merged CSP is not guaranteed. It is possible that the style-src directive could come before the script-src directive.

It is best to avoid using multiple CSP meta tags to specify a CSP. If you need to specify a CSP for a page, it is best to do so in the response headers.


From these responses it can be concluded that:

  • CSP headers ('Content-Security-Policy') are prioritized and should be used where possible.
  • Multiple meta tags with CSP are possible. However, this is not recommended.
  • When both CSP headers and meta tags are used, the CSP headers only are applied.
  • When multiple meta tags are used, depending on the browser implementation, they may be merged.

WordPress public routes, both API and standard routes

I wanted a list of public WordPress routes for quickly finding routes to test and check security issues, so I generated a list using Bard AI.

My first attempt only provided the API routes. They can be seen below:

===

The following is a list of all routes a site on WordPress can be publicly accessed from by default:

  • /wp-json/ – The root of the WordPress REST API.
  • /wp-json/wp/v2/ – The namespace for the WordPress core REST API.
  • /wp-json/wp/v2/posts/ – A route for managing posts.
  • /wp-json/wp/v2/posts/{id}/ – A route for managing a specific post, where {id} is the post ID.
  • /wp-json/wp/v2/pages/ – A route for managing pages.
  • /wp-json/wp/v2/pages/{id}/ – A route for managing a specific page, where {id} is the page ID.
  • /wp-json/wp/v2/categories/ – A route for managing categories.
  • /wp-json/wp/v2/categories/{id}/ – A route for managing a specific category, where {id} is the category ID.
  • /wp-json/wp/v2/tags/ – A route for managing tags.
  • /wp-json/wp/v2/tags/{id}/ – A route for managing a specific tag, where {id} is the tag ID.
  • /wp-json/wp/v2/users/ – A route for managing users.
  • /wp-json/wp/v2/users/{id}/ – A route for managing a specific user, where {id} is the user ID.
  • /wp-json/wp/v2/media/ – A route for managing media.
  • /wp-json/wp/v2/media/{id}/ – A route for managing a specific media item, where {id} is the media item ID.
  • /wp-json/wp/v2/comments/ – A route for managing comments.
  • /wp-json/wp/v2/comments/{id}/ – A route for managing a specific comment, where {id} is the comment ID.
  • /wp-json/wp/v2/settings/ – A route for managing settings.
  • /wp-json/wp/v2/search/ – A route for searching.

In addition to these default routes, WordPress also allows plugins and themes to register their own custom routes.

It is important to note that the WordPress REST API is exposed by default, but it can be disabled in the WordPress admin settings.

===

I tried again asking for non-API routes, and got a list of important standard routes:

===

The following is a list of all non-API routes a site on WordPress can be publicly accessed from by default:

  • / – The home page of the site.
  • /about/ – The about page of the site.
  • /contact/ – The contact page of the site.
  • /blog/ – The blog page of the site.
  • /category/{slug}/ – A page for displaying all posts in a specific category, where {slug} is the category slug.
  • /tag/{slug}/ – A page for displaying all posts in a specific tag, where {slug} is the tag slug.
  • /archives/{year}/{month}/ – A page for displaying all posts published in a specific year and month.
  • /author/{author_name}/ – A page for displaying all posts published by a specific author, where {author_name} is the author’s name.
  • /wp-login.php – The WordPress login page.
  • /wp-register.php – The WordPress registration page.
  • /wp-admin/ – The WordPress admin dashboard.

In addition to these default routes, WordPress also allows plugins and themes to register their own custom routes.

It is important to note that the WordPress admin dashboard is not publicly accessible by default, but it can be made publicly accessible by changing the WordPress admin settings.

===

This is sufficient for me now, but please note, this is probably not an extensive list.
For an extensive list, please check the official WordPress documentation.

WordPress backup (BackWPup) WARNING File name is too long to save correctly in TarGz archive – tar and zip file name limits explored

While attempting to backup WordPress, I noticed that a warning was being shown.
This warning stated that “WARNING: File name wp-content/uploads/… is too long to be save correctly in TarGz archive”.
The warning seems clear enough, but how long exactly is “too long”, and can this be improved upon?

Searching online gave a few examples of people with similar issues:

The consensus on fixing this seems to be to use “zip” instead.
This is also the officially provided solution for this: WARNING: FILE NAME TOO LONG TO BE SAVED

OK, if you don’t care about any further details, this is the solution. Use “zip”.
I was interested as to the limitations of tar and zip, and if they could be improved upon, so I asked through Bard AI with an appropriate prompt shown below:

===

When creating a backup with tar.gz, I sometimes get a file name too long warning. It seems that only 100 character file names are supported. Is this 100-character limit something that applies to all available tar executables? Is there a way to allow longer file names? Does this limitation differ by Linux, Windows, or Linux distribution/version?

===
The 100-character limit on file names in tar archives is a limitation of the original tar format, which was defined in 1979. This format is still used by many tar implementations today, including the default format used by the GNU tar command.

However, there are also a number of tar implementations that support longer file names. One example is GNU tar with the --format=gnu option. This format allows for file names of up to 255 characters.

Another option is to use a different archive format altogether. For example, the zip format supports file names of up to 65535 characters.

Whether or not you can use longer file names in a tar archive will depend on the tar implementation that you are using and the format of the archive.

To answer your specific questions:

  • The 100-character limit on file names does not apply to all available tar executables. There are a number of tar implementations that support longer file names.
  • There are a few ways to allow longer file names in a tar archive. One option is to use the GNU tar command with the --format=gnu option. Another option is to use a different archive format altogether, such as zip.
  • The limitation on file name length in tar archives does not differ by Linux, Windows, or Linux distribution/version. It is a limitation of the original tar format, which is used by many tar implementations on all platforms.

If you are creating a tar archive, and you get a file name too long warning, you can try one of the following:

  • Use a tar implementation that supports longer file names, such as GNU tar with the --format=gnu option.
  • Use a different archive format altogether, such as zip.
  • Rename the files with longer names to shorter names.
  • Split the files with longer names into multiple files with shorter names.

===

The important parts from above are:
  • tar file name character limit is 100 by default
  • –format=gnu option makes the file name character limit 255
  • zip file name character limit is 65535
OK, so from this it can be concluded that zip file names can be long enough for all but extreme cases.
100 characters is definitely very small, so is an issue.
255 is still not very large, so zip definitely is safer.
I asked AI again if there was a way to increase the character limit further for tar, but it stated there was no way to do this. Maybe there is, but even if, it probably isn’t easy to do, so use zip seems like the way to go.

List of known/common standardized JSON Schema properties.

The JSON Schema standard is extensive and descriptive, but it can lead to taking too much time to quickly find the name of a property, etc.
I decided to generate a list of important JSON Schema properties so they can be easy to find when needed.
The following was generated using Bard AI, and seems to be accurate.

Please provide a list of all known standardized properties in jsonschema with the property name, followed by a colon + space delimiter, and the followed by a description of the property. Each should be on one new line.


The following is a list of all known standardized properties in JSON Schema, with the property name, followed by a colon + space delimiter, and then followed by a description of the property, each on a new line:

  • $schema: The URI of the JSON Schema version used to define the schema.
  • $ref: A reference to another JSON Schema that defines the schema for this object.
  • $id: A unique identifier for the schema.
  • title: A human-readable title for the schema.
  • description: A human-readable description of the schema.
  • type: The data type of the value that the schema validates.
  • enum: An array of valid values for the schema.
  • const: A constant value that the schema validates.
  • multipleOf: A number that the value must be divisible by.
  • maximum: The maximum value that the schema validates.
  • exclusiveMaximum: A boolean value indicating whether the maximum value is exclusive or inclusive.
  • minimum: The minimum value that the schema validates.
  • exclusiveMinimum: A boolean value indicating whether the minimum value is exclusive or inclusive.
  • maxLength: The maximum length of a string that the schema validates.
  • minLength: The minimum length of a string that the schema validates.
  • pattern: A regular expression that the value must match.
  • maxItems: The maximum number of items in an array that the schema validates.
  • minItems: The minimum number of items in an array that the schema validates.
  • uniqueItems: A boolean value indicating whether the items in an array must be unique.
  • maxProperties: The maximum number of properties in an object that the schema validates.
  • minProperties: The minimum number of properties in an object that the schema validates.
  • required: An array of property names that must be present in an object that the schema validates.
  • dependentRequired: An object mapping property names to arrays of property names. If a property that is present in the first array is present in the object, then all of the properties in the second array must also be present.
  • additionalProperties: A boolean value indicating whether additional properties are allowed in an object that the schema validates.
  • properties: An object mapping property names to JSON Schemas that define the schemas for those properties.
  • patternProperties: An object mapping regular expressions to JSON Schemas that define the schemas for properties that match those regular expressions.
  • allOf: An array of JSON Schemas that the value must validate against.
  • anyOf: An array of JSON Schemas that the value must validate against at least one of.
  • oneOf: An array of JSON Schemas that the value must validate against exactly one of.
  • not: A JSON Schema that the value must not validate against.

Please note that this list is not exhaustive, and there may be other standardized properties in JSON Schema that are not listed here.

 

How to create a valid definitions only jsonschema file?

Sometimes it is useful to group jsonschema to be referenced elsewhere when desired like a utility module but for schema.
However, it is a little confusing on how to group these definitions.
There is also the issue of making sure the schema is still valid because jsonschema libraries that handle things such as validation may not accept custom formats.

I asked Bard AI, and got an appropriate response, so I have shared the information below:

I want to create a jsonschema file that only contains definitions(jsonschema that can be referenced).
I don’t need the root object to be a usable schema.
I want the file to be a valid jsonschema.

Is this possible, and please provide an example.

Yes, it is possible to create a JSON schema file that only contains definitions. This is a perfectly valid way to use JSON schema, and it can be useful for organizing your schemas and making them more reusable.

Here is an example of a JSON schema file that only contains definitions:

JSON
{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "definitions": {
    "MediaObject": {
      "type": "object",
      "required": ["type", "url"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["image/jpeg", "image/png"]
        },
        "url": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "Person": {
      "type": "object",
      "required": ["name", "age"],
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }
}

This schema file defines two schemas: MediaObject and Person. These schemas can then be referenced from other schema files using the $ref keyword.

For example, the following schema file references the MediaObject and Person schemas defined in the previous example:

JSON
{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["mediaObject", "person"],
  "properties": {
    "mediaObject": {
      "$ref": "#/components/schemas/MediaObject"
    },
    "person": {
      "$ref": "#/components/schemas/Person"
    }
  },
  "components": {
    "schemas": {
      "MediaObject": {
        "$ref": "#/definitions/MediaObject"
      },
      "Person": {
        "$ref": "#/definitions/Person"
      }
    }
  }
}

This schema file is valid, even though the root object is not a usable schema. This is because the root object is only used to define the MediaObject and Person schemas, which can then be referenced from other schema files.

You can use this approach to create a library of reusable schema definitions. This can make your schemas more modular and easier to maintain.

I was reading the jsonschema specification draft, and noticed that the “$defs” property was used to group definitions. I have noticed you and others have used the “definitions” property to group definitions. Which one is better, and why?

The $defs keyword was introduced in JSON Schema draft 2019-09. It is a newer and more standardized way to group definitions.

The definitions keyword is still valid, but it is deprecated. It is recommended that new schemas use the $defs keyword instead.

There are a few reasons why the $defs keyword is better:

  • It is more standardized. The definitions keyword was not defined in the JSON Schema specification, but was rather a convention that was widely used. The $defs keyword is defined in the JSON Schema specification, so it is more likely to be supported by all JSON schema implementations.
  • It is more explicit. The definitions keyword could be used for other purposes in addition to grouping definitions. For example, it could be used to define a set of named anchors for use in JSON Pointer expressions. The $defs keyword is specifically for grouping definitions, so it is more explicit and less likely to be confused with other features of JSON Schema.
  • It is more future-proof. The JSON Schema specification is still under development, and it is possible that the definitions keyword could be deprecated in the future. The $defs keyword is a newer keyword, so it is more likely to be supported in the future.

Overall, the $defs keyword is the better choice for grouping definitions in JSON Schema. It is more standardized, more explicit, and more future-proof.

However, it is important to note that the definitions keyword is still valid, and there are many existing JSON schemas that use it. If you are working with an existing JSON schema that uses the definitions keyword, there is no need to change it to use the $defs keyword.

As stated, if the root schema only provides the definitions, then it is valid, and although the “definitions” property is often used for grouping definitions, it has actually been standardized to be “$defs” instead, but definitions is still valid and has been used from before the property was standardized.

When the URL of an iframe is changed within the iframe, the iframe element’s “src” attribute does not change. What is the reasoning for this?

I asked Bard AI about why iframes don’t update the src attribute when the content changes, and got a very logical response.

Thinking about it, one obvious point is that the content within the iframe should not leak any data in the page. This is because in the iframe, the content may include something like an OAuth login, or query state. It is possible that the query parameters could contain something like an OAuth code or sensitive search queries, which should definitely not be shared with the parent DOM.

The full response is below.

There are a few reasons why the iframe element’s src attribute does not change when the URL of an iframe is changed within the iframe.

First, it is important to remember that an iframe is a separate document from the parent document. When you change the URL of an iframe within the iframe, you are actually changing the URL of the embedded document, not the iframe element itself.

Second, the src attribute of an iframe element is read-only. This means that once the src attribute is set, it cannot be changed.

Finally, there is a security risk associated with allowing iframes to change their own src attribute. If an iframe were able to change its own src attribute, it could potentially load malicious content from a different domain.

To avoid these problems, if you need to change the URL of an iframe, you must do so from the parent document. You can do this using JavaScript to set the src attribute of the iframe element.

Here is an example of how to change the URL of an iframe using JavaScript:

JavaScript
// Get the iframe element
var iframe = document.getElementById('myIframe');

// Set the src attribute of the iframe element
iframe.src = 'https://new-url.com';

When you set the src attribute of an iframe element using JavaScript, the iframe will be reloaded with the new URL.

It is important to note that you can only change the URL of an iframe if the iframe is from the same domain as the parent document. If the iframe is from a different domain, you will need to use a cross-origin resource sharing (CORS) request to change the URL of the iframe.

How to mark an npm project as for Node.js or for browser or for both?

One issue I have often run into when using npm packages is not supporting the browser.
It is common for even a simple utility package to have a dependency on an npm package and so only work in Node.js. It would be nice if this could be detected quickly, especially automatically.
I asked this question to Bard AI, and got a useful response. The response doesn’t solve the issue for all packages as it requires certain optional properties to be set, but if they are set, then it can be decided what environment support exists.

Is there a common or official way to mark an npm project as for usage of Node.js(not browser), vice-versa, and both?

Yes, there are two ways to mark an npm project as for usage of Node.js (not browser), vice-versa, and both.

  • Using the engines field in the package.json file. This is the official way to specify the runtime environment that a package requires. The engines field is a list of objects, each of which specifies a minimum version of a particular runtime environment. For example, to specify that a package requires Node.js 16 or later, you would add the following to the engines field:
"engines": {
  "node": ">=16"
}
  • Using the browserslist field in the package.json file. This field specifies the browsers that a package supports. If you want to specify that a package is only for Node.js, you would set the browserslist field to an empty array. For example:
"browserslist": []

If you want to specify that a package is for both Node.js and the browser, you would set the browserslist field to a list of browsers that the package supports. For example:

"browserslist": ["last 2 versions", "not ie <= 11"]

The browserslist field is used by the npm command to determine which packages to install when you run npm install. For example, if you have a package that is only for Node.js, and you run npm install, the npm command will only install the packages that are listed in the engines field.

I hope this helps! Let me know if you have any other questions.

How to parse the datetime format used on lines in phperror.log?

The following was returned using Bard AI. It provided a good response, so I am sharing below:

Prompt used: “For the $format argument used in DateTime::createFromFormat of PHP, what format should I use to parse “10-Sep-2023 00:13:12 UTC”?”.

The following format can be used to parse the string 10-Sep-2023 00:13:12 UTC using the DateTime::createFromFormat function in PHP:

$format = 'd-M-Y H:i:s T';

This format specifies the following:

  • d: The day of the month, as a two-digit number.
  • M: The month, as a three-letter abbreviation.
  • Y: The year, as a four-digit number.
  • H: The hour, as a two-digit number in 24-hour format.
  • i: The minute, as a two-digit number.
  • s: The second, as a two-digit number.
  • T: The time zone, as a single-letter abbreviation.

In this case, the time zone is UTC, which is the Coordinated Universal Time.

To parse the string 10-Sep-2023 00:13:12 UTC, we can use the following code:

PHP
$dateTime = DateTime::createFromFormat($format, '10-Sep-2023 00:13:12 UTC');
Use code with caution. Learn more

content_copy

This will create a DateTime object representing the specified date and time in UTC.

We can then use the DateTime object to get the individual components of the date and time, or to perform other operations, such as formatting the date and time in a different format.

IFrame src is not updating when frame URL changes. Why does this happen?

Recently, I have been using Bard quite a lot because it has proven to be quite helpful. This time it was so much better than searching Google and DuckDuckGo that I decided to share it in a post for everybody’s reference.

When the URL of an iframe is changed within the iframe, the iframe element’s “src” attribute does not change. What is the reasoning for this?

There are a few reasons why the iframe element’s src attribute does not change when the URL of an iframe is changed within the iframe.

First, it is important to remember that an iframe is a separate document from the parent document. When you change the URL of an iframe within the iframe, you are actually changing the URL of the embedded document, not the iframe element itself.

Second, the src attribute of an iframe element is read-only. This means that once the src attribute is set, it cannot be changed.

Finally, there is a security risk associated with allowing iframes to change their own src attribute. If an iframe were able to change its own src attribute, it could potentially load malicious content from a different domain.

To avoid these problems, if you need to change the URL of an iframe, you must do so from the parent document. You can do this using JavaScript to set the src attribute of the iframe element.

Here is an example of how to change the URL of an iframe using JavaScript:

JavaScript
// Get the iframe element
var iframe = document.getElementById('myIframe');

// Set the src attribute of the iframe element
iframe.src = 'https://new-url.com';

When you set the src attribute of an iframe element using JavaScript, the iframe will be reloaded with the new URL.

It is important to note that you can only change the URL of an iframe if the iframe is from the same domain as the parent document. If the iframe is from a different domain, you will need to use a cross-origin resource sharing (CORS) request to change the URL of the iframe.