Code Book, part 4 (Obscure Coding Standards)

Written by Chris Graham
« Return to Code Book table of contents

This section covers coding standards that should be upheld, but are either:
  1. relate to a very specific Composr scenario that most developers won't be facing day-to-day
  2. so obvious you don't need to learn them in advance either

It serves as a reference guide for settling disagreements, as a general reference when doing more extensive quality reviews, and a reference for what some of our automated tests do.



Back-end programming

General

Standard Reason Scope Test method Notes
1)
Export metadata
Standards compliance Composr development + Manually Export metadata using seo_meta_load_for and set_extra_request_metadata for content modules supporting it.
2)
Never include <? within your PHP source
Portability All development Code Quality Checker PHP short_tags option may be on. This string is used within XML so is fairly common to type in; if you need it append two strings together to form it so that it doesn't have to be literally written into the code.
3)
Any page should be accessible as standalone
Usability All development Manually You shouldn't add modules that are never intended to be used independently, because they will come up on the sitemap. If you intend to write some kind of helper script that may be called by a module then either use an "entry-point script" for that or build the functionality into the module file itself (you are allowed to exit out of a module with your own HTTP headers etc rather than returning Tempcode).
4)
Write appropriate hooks etc for new content types
Consistency Composr development + Manually When adding new content types remember to write all appropriate hooks for them (e.g. search hooks). And implement standard systems like SEO metadata, feedback systems, validation, and permissions.
5)
Communicate upload limits
Usability Product development only Manually Show the appropriate maximum-upload size on all screens that support file uploads, unless the size is very unlikely to be reached by the user (e.g. just uploading an avatar). Composr has a standard mechanism to do this, which can be automated within CRUD modules. For code examples search the code for get_upload_limit_config_url.
6)
Don't define too many functions in a single file
Portability: PHP memory_limit setting / performance Composr development + Composr development mode sets a low memory_limit Instead put the script into code files that are loaded only when needed.
7)
Pass in extra useful template parameters
Themeing Product development only Manually Pass in any additional unused parameters to the template where they might be useful; raw timestamps, IDs, etc.
8)
E-mail subject lines must be unique, or the e-mail sender must be a specific user (not the website itself)
Usability Composr development + Manually This convention makes e-mails easier to scan in an inbox and stops incorrect automatic threading.
9)
Use cms_ini_set
Portability Product development only Manually Use cms_ini_set rather than ini_set, as it allows us to control for factors such as ini_set being disabled on the hosting platform (some hosts do this for security reasons).
10)
Block access when closed
Stability All development Manually Any URL that a user may reasonably navigate to manually that is not passed through index.php, must show the closed site message by its own means. Look to see how other code does it for example.

Files

Standard Reason Scope Test method Notes
11)
1 KB = 1024 bytes, etc
Consistency Product development only Manually We don't say KiB or use 1000s. People don't understand KiB (the term never caught on), and 1024 is the long term convention in computing.
12)
No .php files in writable directories
Portability Product development only Automated test async_tests/suphp suPHP will not allow .php files in directories with group/other write permissions.

Log files

Standard Reason Scope Test method Notes
13)
Define log file in a hook
GDPR, Administration Composr development Manually A systems/logs hook needs to define that your log exists. This allows the log purger to clear out old records, and the administrative error-log interface to find your log.
14)
Use correct date format
GDPR Composr development Manually Start your log entries using the output of loggable_date(). This consistent date formatting will allow the log purger to read the log. Multiple lines per entry and lead-in text at the top of the log are allowed; these special lines should not include the date/time. Other than this function there's no explicit log-writing API, because it's pretty standard PHP file I/O.
15)
Lock your file when writing
Stability Composr development Manually Multiple processes may want to write to the log at the same time. Look how other logging code handles locking. In rare situations it may be guaranteed an operation is not going to happen concurrently, in which case you can forget about locking.
16)
Store log as data_custom/whatever.log
Security Composr development Manually This allows the default Apache .htaccess to deny web access to the log. The only exception should be logs which are created by default, which must be .php files with some lead-in code to prevent PHP command execution (using .php is the only 100%-reliable way to prevent unintended file download by URL access).
17)
Do not create log by default
Security Composr development Manually Logs should usually only be used if the standard file has been pre-created by hand. This avoids bloated unneeded logs that may not be properly secured against unwanted access. See the note above for stipulations around the exception to this rule.
18)
Reference in web.config file
Security Composr development Manually We support IIS, which does not support wild-card blocking of file access. So we must manually block access to each individual log file.

URLs and file paths

Standard Reason Scope Test method Notes
19)
Don't append to URLs in templates
URL schemes All development Manually Do not try and appending something to a URL inside a template, unless it is a URL to a helper script (rather than a screen) or if you have explicitly disabled SEO for the URL. URL schemes involve different URL structures. Pass in all the URLs you need to the template so you don't need to deploy hacks.
20)
Don't assume directories already exist to write into
Shared installs: multiple sites with one Composr install, GAE Product development only Manually If running a blank custom directory, none of the bundled directory structure will be initially present. You must therefore detect and auto-create missing directories, using make_missing_directory.

Databases

Standard Reason Scope Test method Notes
21)
Don't require write queries on normal page views
Stability, Performance Product development only Manually Some webhosts will restrict SQL write permission if a database size limit is exceeded, so any routine write queries should have the $fail_ok option set so that it doesn't take the whole site down.
22)
Do maintenance using cms_register_shutdown_function_safe
Performance Product development only Manually Non-critical maintenance such as logging, updating view counts, or deleting expired records, should be done at script end and using the cms_register_shutdown_function_safe function. This is to decrease the time before rendering the page output. Note that we use the cms_register_shutdown_function_safe instead of the register_shutdown_function function, as a minority of servers do not support register_shutdown_function.
23)
Use statistical_update_model function for controlling view count maintenance, and increment directly
Performance Product development only Manually The statistical_update_model function does a number of checks to see if and how view counts should change. Use this function in the same pattern as it is used elsewhere in the code. Do not increment by explicitly passing in a new view count, as that would assume the view count hasn't changed since it came out of the database – run a query to directly increment from the in-database field.
24)
Stay within common denominator of limits
Portability Product development only Table creation code checks There are maximum numbers of indices, fields, fields in keys and indexes, total field size in keys and indexes, length of field names, and length of table names.

Templates and Interfaces

Standard Reason Scope Test method Notes
25)
Nest your templates
Themeing Composr development + Manually Templates should nest, not be split up into start/end pairs.
26)
Use handle_max_file_size ($hidden) when using upload fields so that your form has the right file-size limits on it
Usability for webmasters: stops nasty server-side upload-limit errors Composr development + Manually

Modifying core classes

Standard Reason Scope Test method Notes
27)
Object orientated principles
Technical debt Product development only Use object-orientated principles properly where Composr does already. For example, forum drivers all have a database object as a property, rather than referencing the global FORUM_DB object. This is because they provide a core service and cannot make assumptions about the environment (e.g. it must be possible to have multiple simultaneous forum drivers running).

Blocks

Standard Reason Scope Test method Notes
28)
Blocks should not exit
Stability Product development only Automated test async_tests/blocks If a block hits an error condition it must return an error message, not call a function like warn_exit. An error on a block can't be a fatal thing.

Attachments

Standard Reason Scope Test method Notes
29)
Remember posted Comcode might be invalid
Stability All development Manually If you are supporting Composr attachments in a field, run the check_comcode function on the Comcode that references the attachments before the main row for the content is added to the database. This ensures the Comcode is valid, so you can proceed to add the content row (using the integer 0 temporarily as the field value for where the Comcode will be placed). The attachment Comcode can then be fully parsed (given the ID of the content row, so it can store its security properly) and then the content row updated with the new content language string ID for that parsed Comcode.

Comcode parser/renderer code

Standard Reason Scope Test method Notes
30)
No context-sensitivity
Stability All development Manually When programming the Comcode system, never allow Comcode to become context-sensitive (e.g. behaving differently when run from different URL paths).
31)
Don't use require_javascript or require_css
Stability: cache safety All development Manually When implementing tags, CSS must all be in global.css, and any JavaScript must be by using a symbol to load the JavaScript file – this is because any inclusion code put in the PHP rendering code only runs when the Comcode is first compiled, and not when it is loaded out of the cache.

Regular expressions

If you are writing regular expressions to extract data from HTML, you should anticipate…
Standard Reason Scope Test method Notes
32)
…there may be extra whitespace (there may be extra spaces inside tag definitions)
33)
…whitespace may come in other forms than the \t symbol (there may be tabs)
34)
…HTML used instead of XHTML. (there may be <br> instead of <br />)
35)
…that tags may be written in upper case
36)
…attribute quotes can be given as single-quotes as well as double quotes, and attribute contents may span multiple lines
37)
…there may be whitespace around tag-contents
38)
…tag contents may not be properly entity-encoded
39)
…quoted data may contain quotes of the other-type (there may be <a title="He's saying hello">)

You may assume…
Standard Reason Scope Test method Notes
40)
…a tag opener/closer stays on one line
41)
…attribute values are quoted
42)
…the text is in either well-formed SGML (HTML) or well-formed XML (XHTML)

Installation code

Standard Reason Scope Test method Notes
43)
Installation code must respect the multi-language system
Internationalisation Product development only Manually Make sure the lang_code_to_default_content function is used where appropriate in installation code. This function puts in content language strings to the database such that they get stored automatically for all translations available on the installation.
44)
Upgrades must be handled correctly
Stability Product development only Manually Make sure that modules upgrade properly between major versions of Composr, and preferably between all versions. Do not assume a module will never be upgraded: if your module has undergone database structure revisions then you must make sure there is upgrade code to apply these revisions. See how existing code does it for examples.
45)
Reinstalls must be handled correctly
Stability Product development only Automated test cli_tests/installer If a module is reinstalled, it should not give errors about existing tables or privileges. For this to work, the uninstall function must fully uninstall what the install function creates.

Cryptography

Standard Reason Scope Test method Notes
46)
Do not use hashing in cryptographic randomness
Security Product development only Manually When developing cryptographic functions in crypt.php to generate randomness of some kind, do not use hashing algorithms in the process. Hashing algorithms, particularly MD5, carry the risk of clashes (when two or more strings evaluate to the same hash). Furthermore, they defeat the purpose of cryptography because they increase the risk of hackers being able to predict the randomness.
47)
Always use cryptographically-secure entropy when generating cryptographically-secure randomness
Security Product development only Manually When developing cryptographic functions in crypt.php to generate randomness of some kind, use cryptographically-secure entropy in every step of the process involving randomness. If even one random number/string/etc is not generated with cryptographically-secure entropy, the entire process is compromised and left open to prediction by hackers.
48)
Do not use the site salt on non-volatile data (e.g. passwords)
Stability Product development only Manually When hashing passwords or other non-volatile data, do not salt them with the site salt. Instead, generate a specific salt (such as for the member) and store that along with the hashed password. Using the site salt can cause lock-outs in the rare event the site salt gets changed or re-generated. The site salt is more appropriate for URL hashes (e.g. verification), cookies, hashed session IDs, caches, and temporary files or data.

Front-end programming

Spelling/grammar/lexicon

(examples of what not to do are in italics)

Standard Reason Scope Test method Notes
49)
Don't spell things rong or use incorrect grammar
Usability Composr development + Automated test async_tests/lang_spelling, Automated test sync_tests/__lang_spelling_epic, Automated test async_tests/lang_grammar
50)
Be careful where you put your apostrophe's
Usability Composr development + Manually + use the .ini files with Microsoft Word's checking tools Apostrophes are not used for plurals.
51)
When needed, add comments to the language files to define context
Internationalisation Product development only Manually For an example of how to do this, see global.ini.
52)
Use quotes consistently
Consistent UI Product development only Manually When quoting phrases use double quotes (speech marks), which in language files and templates would generally be done using the HTML ldquo and rdquo entities.
When quoting single words or terms use single quotes, which in language files and templates would generally be done using the HTML lsquo and rsquo entities.
When quoting something code-related like a language keyword use Comcode's tt or HTML's kbd.
When referencing keyboard key names, refer to them like Ctrl or Shift or Option or Alt: capitalise the first letter.
When in general trying to draw attention to a word/term/phrase that isn't part of any quotation, use bold.
53)
Don't use software-specific terms on the main website
Consistent UI Composr development + Manually Composr 'brands' or unique terminology ('Zone', 'Comcode', …) should not be seen on the main website.
54)
Use the term ‘link’ correctly
Consistent UI Product development only Manually A ‘link’ is specifically a hyperlink (i.e. something that can be clicked), it is not a synonym for ‘URL’. Most of the time in code you will use the term ‘URL’. A ‘link’ goes to a ‘URL’.

Markup/Tempcode

Standard Reason Scope Test method Notes
55)
Exclude robots appropriately
SEO All development Manually You need to stop search engines indexing utility scripts, or pages that only should be navigated to manually by a human. This can be done using an attach_to_screen_header call that adds a meta tag for HTML pages, a NOINDEX parameter to the STANDALONE_HTML_WRAP template, or a X-Robots-Tag HTTP header for non-HTML pages.

JavaScript

Standard Reason Scope Test method Notes
56)
Use modern DOM (so no document.all, or window.images)
Standards compliance Product development only Automated test sync_tests/web_resources document.all, form.foo, etc, are all non-standard (even though they're commonplace) – use getElementById etc.
57)
Don't use any deprecated methods (so no escape)
Standards compliance Product development only Automated test sync_tests/web_resources Instead of escape, use encodeURIComponent.
58)
Choose wisely in how to force form submission
Framework Composr development + Manually There are cases where you need to manually submit a form, e.g. if the user clicks a button to submit a form but your validation requires a promise to pass first. form.submit(); will submit the form without calling event handling, while $dom.trigger(form, 'submit'); will call event handling. Choose which makes sense for your situation.
59)
Use localName not nodeName
Stability Composr development + ESLint Using nodeName is not reliable when namespaces are involved, and may also return in upper case. localName is much more reliable, although only works on HTML Element DOM nodes not any DOM node.

Documentation

Standard Reason Scope Test method Notes
60)
Use top-level heading correctly
Communication Product development only Automated test async_tests/tutorial_quality The top level heading must be structured correctly, including attributing the tutorial author. Refer to existing tutorials for an example.
61)
Include a table of contents
Communication Product development only Automated test async_tests/tutorial_quality Include a table of contents after the introduction paragraph and before subsequent titles. Refer to existing tutorials for an example.
62)
Include a sensible title structure
Communication Product development only Automated test async_tests/tutorial_title_structure Have a title structure that uses the title levels sensibly.
63)
Standardised image linking
Communication, consistency Product development only Automated test async_tests/tutorial_quality, Automated test async_tests/tutorial_image_consistency Include images via Comcode media tags to files in data_custom/images/docs/<tutorial_name>. Typically use floating to put images to the right of text content, and use the surround Comcode tag to hold things together. Refer to existing tutorials for an example.
64)
Meet minimum image density
Communication: visual learners appreciate images Product development only Automated test async_tests/tutorial_quality Have a reasonable number of images per tutorial.
65)
Define a keyword table
Communication Product development only Automated test async_tests/tutorial_quality Define new keywords in a table near the bottom of the tutorial. Refer to existing tutorials for an example.
66)
Have a See Also list
Communication: strong cross-linking Product development only Automated test async_tests/tutorial_quality Provide a list of other tutorials to reference. Refer to existing tutorials for an example.
67)
Link to other tutorials using the _SEARCH zone
Stability Product development only Automated test async_tests/tutorial_quality By linking using the _SEARCH zone we allow tutorials to run from different contexts, but also to link to tutorials within the same zone as they are in when possible (so we can host multiple copies of the documentation with correct internal cross-linking).
68)
Use code tags correctly
Communication: syntax highlighting Product development only Automated test async_tests/tutorials_codebox Any Comcode code tag must specify the language of the code, which must be one of the languages listed in the automated test (we try and match ones we can syntax highlight).
69)
Supply tutorial tags
Communication: strong cross-linking Product development only Automated test async_tests/tutorial_quality, Automated test async_tests/tutorials_all_linked Provide a list of applicable tags for the tutorial at the bottom. At least one of these should be the title of a broad documentation category (the first of which is where the icon is drawn from). Tags that do not refer to a documentation category must refer to a Composr addon codename. If you refer to an addon, the addon's registry hook must refer back in it's list of tutorials. Refer to existing tutorials for an example.
70)
Include a tutorial date
Communication Product development only Automated test async_tests/tutorial_quality Include the date the tutorial was written on. Refer to existing tutorials for an example.
71)
Include a rating block
Product feedback Product development only Automated test async_tests/tutorial_quality Include a rating block. Refer to existing tutorials for an example.
72)
Include a summary
Communication: use on indexes Product development only Automated test async_tests/tutorial_quality Include a summary. Refer to existing tutorials for an example.

Agency standards

Standard Reason Scope Test method Notes
73)
Use a staging server system
Deployment, collaboration Projects Manually The Staging Servers tutorial lays out processes for deploying in a professional way.
74)
Run Health Check
Deployment, stability Projects Manually Run Admin Zone > Tools > Health Check to confirm things are good.
75)
Use a good upgrade and maintenance process
Deployment, collaboration Projects Manually The Professional upgrading tutorial lays out a good process for maintaining and upgrading websites.

Feedback

Please rate this tutorial:

Have a suggestion? Report an issue on the tracker.