forked from grumpydevelop/federator
		
	initial import
This commit is contained in:
		
						commit
						ef25c5b3af
					
				
					 23 changed files with 1693 additions and 0 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
composer.lock
 | 
			
		||||
vendor
 | 
			
		||||
php/version.php
 | 
			
		||||
							
								
								
									
										369
									
								
								.phan/config.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								.phan/config.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,369 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Phan\Issue;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This configuration file was automatically generated by 'phan --init --init-level=1'
 | 
			
		||||
 *
 | 
			
		||||
 * TODOs (added by 'phan --init'):
 | 
			
		||||
 *
 | 
			
		||||
 * - Go through this file and verify that there are no missing/unnecessary files/directories.
 | 
			
		||||
 *   (E.g. this only includes direct composer dependencies - You may have to manually add indirect composer dependencies to 'directory_list')
 | 
			
		||||
 * - Look at 'plugins' and add or remove plugins if appropriate (see https://github.com/phan/phan/tree/v5/.phan/plugins#plugins)
 | 
			
		||||
 * - Add global suppressions for pre-existing issues to suppress_issue_types (https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base)
 | 
			
		||||
 *   - Consider setting up a baseline if there are a large number of pre-existing issues (see `phan --extended-help`)
 | 
			
		||||
 *
 | 
			
		||||
 * This configuration will be read and overlaid on top of the
 | 
			
		||||
 * default configuration. Command line arguments will be applied
 | 
			
		||||
 * after this file is read.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://github.com/phan/phan/wiki/Phan-Config-Settings for all configurable options
 | 
			
		||||
 * @see https://github.com/phan/phan/tree/v5/src/Phan/Config.php
 | 
			
		||||
 *
 | 
			
		||||
 * A Note About Paths
 | 
			
		||||
 * ==================
 | 
			
		||||
 *
 | 
			
		||||
 * Files referenced from this file should be defined as
 | 
			
		||||
 *
 | 
			
		||||
 * ```
 | 
			
		||||
 *   Config::projectPath('relative_path/to/file')
 | 
			
		||||
 * ```
 | 
			
		||||
 *
 | 
			
		||||
 * where the relative path is relative to the root of the
 | 
			
		||||
 * project which is defined as either the working directory
 | 
			
		||||
 * of the phan executable or a path passed in via the CLI
 | 
			
		||||
 * '-d' flag.
 | 
			
		||||
 */
 | 
			
		||||
return [
 | 
			
		||||
 | 
			
		||||
    // The PHP version that the codebase will be checked for compatibility against.
 | 
			
		||||
    // For best results, the PHP binary used to run Phan should have the same PHP version.
 | 
			
		||||
    // (Phan relies on Reflection for some types, param counts,
 | 
			
		||||
    // and checks for undefined classes/methods/functions)
 | 
			
		||||
    //
 | 
			
		||||
    // Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`,
 | 
			
		||||
    // `'8.0'`, `'8.1'`, `'8.2'`, `'8.3'`, `null`.
 | 
			
		||||
    // If this is set to `null`,
 | 
			
		||||
    // then Phan assumes the PHP version which is closest to the minor version
 | 
			
		||||
    // of the php executable used to execute Phan.
 | 
			
		||||
    //
 | 
			
		||||
    // Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist.
 | 
			
		||||
    // (See `backward_compatibility_checks` for additional options)
 | 
			
		||||
    // TODO: Choose a target_php_version for this project, or leave as null and remove this comment
 | 
			
		||||
    'target_php_version' => '8.3',
 | 
			
		||||
 | 
			
		||||
    // If enabled, missing properties will be created when
 | 
			
		||||
    // they are first seen. If false, we'll report an
 | 
			
		||||
    // error message if there is an attempt to write
 | 
			
		||||
    // to a class property that wasn't explicitly
 | 
			
		||||
    // defined.
 | 
			
		||||
    'allow_missing_properties' => false,
 | 
			
		||||
 | 
			
		||||
    // If enabled, null can be cast to any type and any
 | 
			
		||||
    // type can be cast to null. Setting this to true
 | 
			
		||||
    // will cut down on false positives.
 | 
			
		||||
    'null_casts_as_any_type' => false,
 | 
			
		||||
 | 
			
		||||
    // If enabled, allow null to be cast as any array-like type.
 | 
			
		||||
    //
 | 
			
		||||
    // This is an incremental step in migrating away from `null_casts_as_any_type`.
 | 
			
		||||
    // If `null_casts_as_any_type` is true, this has no effect.
 | 
			
		||||
    'null_casts_as_array' => false,
 | 
			
		||||
 | 
			
		||||
    // If enabled, allow any array-like type to be cast to null.
 | 
			
		||||
    // This is an incremental step in migrating away from `null_casts_as_any_type`.
 | 
			
		||||
    // If `null_casts_as_any_type` is true, this has no effect.
 | 
			
		||||
    'array_casts_as_null' => false,
 | 
			
		||||
 | 
			
		||||
    // If enabled, scalars (int, float, bool, string, null)
 | 
			
		||||
    // are treated as if they can cast to each other.
 | 
			
		||||
    // This does not affect checks of array keys. See `scalar_array_key_cast`.
 | 
			
		||||
    'scalar_implicit_cast' => false,
 | 
			
		||||
 | 
			
		||||
    // If enabled, any scalar array keys (int, string)
 | 
			
		||||
    // are treated as if they can cast to each other.
 | 
			
		||||
    // E.g. `array<int,stdClass>` can cast to `array<string,stdClass>` and vice versa.
 | 
			
		||||
    // Normally, a scalar type such as int could only cast to/from int and mixed.
 | 
			
		||||
    'scalar_array_key_cast' => false,
 | 
			
		||||
 | 
			
		||||
    // If this has entries, scalars (int, float, bool, string, null)
 | 
			
		||||
    // are allowed to perform the casts listed.
 | 
			
		||||
    //
 | 
			
		||||
    // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]`
 | 
			
		||||
    // allows casting null to a string, but not vice versa.
 | 
			
		||||
    // (subset of `scalar_implicit_cast`)
 | 
			
		||||
    'scalar_implicit_partial' => [],
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will warn if **any** type in a method invocation's object
 | 
			
		||||
    // is definitely not an object,
 | 
			
		||||
    // or if **any** type in an invoked expression is not a callable.
 | 
			
		||||
    // Setting this to true will introduce numerous false positives
 | 
			
		||||
    // (and reveal some bugs).
 | 
			
		||||
    'strict_method_checking' => true,
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will warn if **any** type of the object expression for a property access
 | 
			
		||||
    // does not contain that property.
 | 
			
		||||
    'strict_object_checking' => true,
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will warn if **any** type in the argument's union type
 | 
			
		||||
    // cannot be cast to a type in the parameter's expected union type.
 | 
			
		||||
    // Setting this to true will introduce numerous false positives
 | 
			
		||||
    // (and reveal some bugs).
 | 
			
		||||
    'strict_param_checking' => true,
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will warn if **any** type in a property assignment's union type
 | 
			
		||||
    // cannot be cast to a type in the property's declared union type.
 | 
			
		||||
    // Setting this to true will introduce numerous false positives
 | 
			
		||||
    // (and reveal some bugs).
 | 
			
		||||
    'strict_property_checking' => true,
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will warn if **any** type in a returned value's union type
 | 
			
		||||
    // cannot be cast to the declared return type.
 | 
			
		||||
    // Setting this to true will introduce numerous false positives
 | 
			
		||||
    // (and reveal some bugs).
 | 
			
		||||
    'strict_return_checking' => true,
 | 
			
		||||
 | 
			
		||||
    // If true, seemingly undeclared variables in the global
 | 
			
		||||
    // scope will be ignored.
 | 
			
		||||
    //
 | 
			
		||||
    // This is useful for projects with complicated cross-file
 | 
			
		||||
    // globals that you have no hope of fixing.
 | 
			
		||||
    'ignore_undeclared_variables_in_global_scope' => false,
 | 
			
		||||
 | 
			
		||||
    // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for,
 | 
			
		||||
    // but aren't available in the codebase, or from Reflection.
 | 
			
		||||
    // (may lead to false positives if an extension isn't loaded)
 | 
			
		||||
    //
 | 
			
		||||
    // If this is true(default), then Phan will not warn.
 | 
			
		||||
    //
 | 
			
		||||
    // Even when this is false, Phan will still infer return values and check parameters of internal functions
 | 
			
		||||
    // if Phan has the signatures.
 | 
			
		||||
    'ignore_undeclared_functions_with_known_signatures' => false,
 | 
			
		||||
 | 
			
		||||
    // Backwards Compatibility Checking. This is slow
 | 
			
		||||
    // and expensive, but you should consider running
 | 
			
		||||
    // it before upgrading your version of PHP to a
 | 
			
		||||
    // new version that has backward compatibility
 | 
			
		||||
    // breaks.
 | 
			
		||||
    //
 | 
			
		||||
    // If you are migrating from PHP 5 to PHP 7,
 | 
			
		||||
    // you should also look into using
 | 
			
		||||
    // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc)
 | 
			
		||||
    // and [php7mar](https://github.com/Alexia/php7mar),
 | 
			
		||||
    // which have different backwards compatibility checks.
 | 
			
		||||
    //
 | 
			
		||||
    // If you are still using versions of php older than 5.6,
 | 
			
		||||
    // `PHP53CompatibilityPlugin` may be worth looking into if you are not running
 | 
			
		||||
    // syntax checks for php 5.3 through another method such as
 | 
			
		||||
    // `InvokePHPNativeSyntaxCheckPlugin` (see .phan/plugins/README.md).
 | 
			
		||||
    'backward_compatibility_checks' => false,
 | 
			
		||||
 | 
			
		||||
    // If true, check to make sure the return type declared
 | 
			
		||||
    // in the doc-block (if any) matches the return type
 | 
			
		||||
    // declared in the method signature.
 | 
			
		||||
    'check_docblock_signature_return_type_match' => true,
 | 
			
		||||
 | 
			
		||||
    // This setting maps case-insensitive strings to union types.
 | 
			
		||||
    //
 | 
			
		||||
    // This is useful if a project uses phpdoc that differs from the phpdoc2 standard.
 | 
			
		||||
    //
 | 
			
		||||
    // If the corresponding value is the empty string,
 | 
			
		||||
    // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`)
 | 
			
		||||
    //
 | 
			
		||||
    // If the corresponding value is not empty,
 | 
			
		||||
    // then Phan will act as though it saw the corresponding UnionTypes(s)
 | 
			
		||||
    // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc.
 | 
			
		||||
    //
 | 
			
		||||
    // This matches the **entire string**, not parts of the string.
 | 
			
		||||
    // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting)
 | 
			
		||||
    //
 | 
			
		||||
    // (These are not aliases, this setting is ignored outside of doc comments).
 | 
			
		||||
    // (Phan does not check if classes with these names exist)
 | 
			
		||||
    //
 | 
			
		||||
    // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']`
 | 
			
		||||
    'phpdoc_type_mapping' => [],
 | 
			
		||||
 | 
			
		||||
    // Set to true in order to attempt to detect dead
 | 
			
		||||
    // (unreferenced) code. Keep in mind that the
 | 
			
		||||
    // results will only be a guess given that classes,
 | 
			
		||||
    // properties, constants and methods can be referenced
 | 
			
		||||
    // as variables (like `$class->$property` or
 | 
			
		||||
    // `$class->$method()`) in ways that we're unable
 | 
			
		||||
    // to make sense of.
 | 
			
		||||
    //
 | 
			
		||||
    // To more aggressively detect dead code,
 | 
			
		||||
    // you may want to set `dead_code_detection_prefer_false_negative` to `false`.
 | 
			
		||||
    'dead_code_detection' => false,
 | 
			
		||||
 | 
			
		||||
    // Set to true in order to attempt to detect unused variables.
 | 
			
		||||
    // `dead_code_detection` will also enable unused variable detection.
 | 
			
		||||
    //
 | 
			
		||||
    // This has a few known false positives, e.g. for loops or branches.
 | 
			
		||||
    'unused_variable_detection' => true,
 | 
			
		||||
 | 
			
		||||
    // Set to true in order to attempt to detect redundant and impossible conditions.
 | 
			
		||||
    //
 | 
			
		||||
    // This has some false positives involving loops,
 | 
			
		||||
    // variables set in branches of loops, and global variables.
 | 
			
		||||
    'redundant_condition_detection' => true,
 | 
			
		||||
 | 
			
		||||
    // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions,
 | 
			
		||||
    // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version).
 | 
			
		||||
    //
 | 
			
		||||
    // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect.
 | 
			
		||||
    // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x.
 | 
			
		||||
    'assume_real_types_for_internal_functions' => true,
 | 
			
		||||
 | 
			
		||||
    // If true, this runs a quick version of checks that takes less
 | 
			
		||||
    // time at the cost of not running as thorough
 | 
			
		||||
    // of an analysis. You should consider setting this
 | 
			
		||||
    // to true only when you wish you had more **undiagnosed** issues
 | 
			
		||||
    // to fix in your code base.
 | 
			
		||||
    //
 | 
			
		||||
    // In quick-mode the scanner doesn't rescan a function
 | 
			
		||||
    // or a method's code block every time a call is seen.
 | 
			
		||||
    // This means that the problem here won't be detected:
 | 
			
		||||
    //
 | 
			
		||||
    // ```php
 | 
			
		||||
    // <?php
 | 
			
		||||
    // function test($arg):int {
 | 
			
		||||
    //     return $arg;
 | 
			
		||||
    // }
 | 
			
		||||
    // test("abc");
 | 
			
		||||
    // ```
 | 
			
		||||
    //
 | 
			
		||||
    // This would normally generate:
 | 
			
		||||
    //
 | 
			
		||||
    // ```
 | 
			
		||||
    // test.php:3 PhanTypeMismatchReturn Returning type string but test() is declared to return int
 | 
			
		||||
    // ```
 | 
			
		||||
    //
 | 
			
		||||
    // The initial scan of the function's code block has no
 | 
			
		||||
    // type information for `$arg`. It isn't until we see
 | 
			
		||||
    // the call and rescan `test()`'s code block that we can
 | 
			
		||||
    // detect that it is actually returning the passed in
 | 
			
		||||
    // `string` instead of an `int` as declared.
 | 
			
		||||
    'quick_mode' => false,
 | 
			
		||||
 | 
			
		||||
    // Override to hardcode existence and types of (non-builtin) globals in the global scope.
 | 
			
		||||
    // Class names should be prefixed with `\`.
 | 
			
		||||
    //
 | 
			
		||||
    // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
 | 
			
		||||
    'globals_type_map' => [],
 | 
			
		||||
 | 
			
		||||
    // The minimum severity level to report on. This can be
 | 
			
		||||
    // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or
 | 
			
		||||
    // `Issue::SEVERITY_CRITICAL`. Setting it to only
 | 
			
		||||
    // critical issues is a good place to start on a big
 | 
			
		||||
    // sloppy mature code base.
 | 
			
		||||
    'minimum_severity' => Issue::SEVERITY_LOW,
 | 
			
		||||
 | 
			
		||||
    // Add any issue types (such as `'PhanUndeclaredMethod'`)
 | 
			
		||||
    // to this list to inhibit them from being reported.
 | 
			
		||||
    'suppress_issue_types' => [],
 | 
			
		||||
 | 
			
		||||
    // A regular expression to match files to be excluded
 | 
			
		||||
    // from parsing and analysis and will not be read at all.
 | 
			
		||||
    //
 | 
			
		||||
    // This is useful for excluding groups of test or example
 | 
			
		||||
    // directories/files, unanalyzable files, or files that
 | 
			
		||||
    // can't be removed for whatever reason.
 | 
			
		||||
    // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`)
 | 
			
		||||
    'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
 | 
			
		||||
 | 
			
		||||
    // A list of files that will be excluded from parsing and analysis
 | 
			
		||||
    // and will not be read at all.
 | 
			
		||||
    //
 | 
			
		||||
    // This is useful for excluding hopelessly unanalyzable
 | 
			
		||||
    // files that can't be removed for whatever reason.
 | 
			
		||||
    'exclude_file_list' => [],
 | 
			
		||||
 | 
			
		||||
    // A directory list that defines files that will be excluded
 | 
			
		||||
    // from static analysis, but whose class and method
 | 
			
		||||
    // information should be included.
 | 
			
		||||
    //
 | 
			
		||||
    // Generally, you'll want to include the directories for
 | 
			
		||||
    // third-party code (such as "vendor/") in this list.
 | 
			
		||||
    //
 | 
			
		||||
    // n.b.: If you'd like to parse but not analyze 3rd
 | 
			
		||||
    //       party code, directories containing that code
 | 
			
		||||
    //       should be added to the `directory_list` as well as
 | 
			
		||||
    //       to `exclude_analysis_directory_list`.
 | 
			
		||||
    'exclude_analysis_directory_list' => [
 | 
			
		||||
        'vendor/',
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    // Enable this to enable checks of require/include statements referring to valid paths.
 | 
			
		||||
    // The settings `include_paths` and `warn_about_relative_include_statement` affect the checks.
 | 
			
		||||
    'enable_include_path_checks' => true,
 | 
			
		||||
 | 
			
		||||
    // The number of processes to fork off during the analysis
 | 
			
		||||
    // phase.
 | 
			
		||||
    'processes' => 1,
 | 
			
		||||
 | 
			
		||||
    // List of case-insensitive file extensions supported by Phan.
 | 
			
		||||
    // (e.g. `['php', 'html', 'htm']`)
 | 
			
		||||
    'analyzed_file_extensions' => [
 | 
			
		||||
        'php',
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    // You can put paths to stubs of internal extensions in this config option.
 | 
			
		||||
    // If the corresponding extension is **not** loaded, then Phan will use the stubs instead.
 | 
			
		||||
    // Phan will continue using its detailed type annotations,
 | 
			
		||||
    // but load the constants, classes, functions, and classes (and their Reflection types)
 | 
			
		||||
    // from these stub files (doubling as valid php files).
 | 
			
		||||
    // Use a different extension from php to avoid accidentally loading these.
 | 
			
		||||
    // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now)
 | 
			
		||||
    //
 | 
			
		||||
    // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`)
 | 
			
		||||
    'autoload_internal_extension_signatures' => [],
 | 
			
		||||
 | 
			
		||||
    // A list of plugin files to execute.
 | 
			
		||||
    //
 | 
			
		||||
    // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`)
 | 
			
		||||
    //
 | 
			
		||||
    // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/v5/.phan/plugins).
 | 
			
		||||
    //
 | 
			
		||||
    // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`)
 | 
			
		||||
    'plugins' => [
 | 
			
		||||
        'AlwaysReturnPlugin',
 | 
			
		||||
        'DollarDollarPlugin',
 | 
			
		||||
        'DuplicateArrayKeyPlugin',
 | 
			
		||||
        'DuplicateExpressionPlugin',
 | 
			
		||||
        'PregRegexCheckerPlugin',
 | 
			
		||||
        'PrintfCheckerPlugin',
 | 
			
		||||
        'SleepCheckerPlugin',
 | 
			
		||||
        'UnreachableCodePlugin',
 | 
			
		||||
        'NonBoolBranchPlugin',
 | 
			
		||||
        'NonBoolInLogicalArithPlugin',
 | 
			
		||||
        'InvalidVariableIssetPlugin',
 | 
			
		||||
        'NumericalComparisonPlugin',
 | 
			
		||||
        'PHPUnitNotDeadCodePlugin',
 | 
			
		||||
        'UnusedSuppressionPlugin',
 | 
			
		||||
        'UnknownElementTypePlugin',
 | 
			
		||||
        'UseReturnValuePlugin',
 | 
			
		||||
        'EmptyStatementListPlugin',
 | 
			
		||||
        'StrictComparisonPlugin',
 | 
			
		||||
        'LoopVariableReusePlugin',
 | 
			
		||||
        'WhitespacePlugin',
 | 
			
		||||
        'PossiblyStaticMethodPlugin',
 | 
			
		||||
        'PHPDocRedundantPlugin',
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    // A list of directories that should be parsed for class and
 | 
			
		||||
    // method information. After excluding the directories
 | 
			
		||||
    // defined in `exclude_analysis_directory_list`, the remaining
 | 
			
		||||
    // files will be statically analyzed for errors.
 | 
			
		||||
    //
 | 
			
		||||
    // Thus, both first-party and third-party code being used by
 | 
			
		||||
    // your application should be included in this list.
 | 
			
		||||
    'directory_list' => [
 | 
			
		||||
        'vendor/phan/phan/src/Phan',
 | 
			
		||||
        'vendor/smarty/smarty/src',
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    // A list of individual files to include in analysis
 | 
			
		||||
    // with a path relative to the root directory of the
 | 
			
		||||
    // project.
 | 
			
		||||
    'file_list' => [],
 | 
			
		||||
];
 | 
			
		||||
							
								
								
									
										41
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
# A system to connect non-federated system to federation (ActivityPub)
 | 
			
		||||
NOTE: this is work in progress, it is nowhere near completion nor function
 | 
			
		||||
 | 
			
		||||
## installation
 | 
			
		||||
install dependencies by using
 | 
			
		||||
 | 
			
		||||
> composer install
 | 
			
		||||
 | 
			
		||||
Upload/copy the files to a directory where php can be run from.
 | 
			
		||||
The files in the htdocs should be the only reachable, the others should not be served via the web server.
 | 
			
		||||
Structure:
 | 
			
		||||
- htdocs <= reachable
 | 
			
		||||
- php <= implementation
 | 
			
		||||
- plugins <= plugin directory for well - plugins
 | 
			
		||||
- config.ini <= the configuration
 | 
			
		||||
 | 
			
		||||
The default config includes a dummy plugin to connect to a non-exisitng server. It accepts any session id and profile name.
 | 
			
		||||
The database is not used yet, but it must be created and the user with given account data must be able to reach it.
 | 
			
		||||
 | 
			
		||||
Needed SQL commands:
 | 
			
		||||
 | 
			
		||||
    create database federator;
 | 
			
		||||
    create user if not exists 'federator'@'localhost' identified by '*change*me*';
 | 
			
		||||
    grant select,insert,update,delete on federator.* to 'federator'@'localhost';
 | 
			
		||||
 | 
			
		||||
This will be changed, but works for the current develop verison.
 | 
			
		||||
 | 
			
		||||
To configure an apache server, add the following rewrite rules:
 | 
			
		||||
 | 
			
		||||
    <Directory /where/ever/you/put/it>
 | 
			
		||||
      RewriteEngine on
 | 
			
		||||
      RewriteBase /
 | 
			
		||||
      RewriteRule ^api/(.+)$ api.php?_call=$1 [L]
 | 
			
		||||
    </Directory>
 | 
			
		||||
 | 
			
		||||
With the dummy plugin and everything installed correctly a
 | 
			
		||||
 | 
			
		||||
> curl -v http://localhost/api/v1/dummy/moo -H "X-Session: somethingvalid" -H "X-Profile: ihaveone"
 | 
			
		||||
 | 
			
		||||
should return a piece of ascii art.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								composer.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								composer.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
{
 | 
			
		||||
    "name": "contentnation/federator",
 | 
			
		||||
    "description": "A federation service",
 | 
			
		||||
    "type": "project",
 | 
			
		||||
    "require": {
 | 
			
		||||
        "smarty/smarty": "^5.3"
 | 
			
		||||
    },
 | 
			
		||||
    "license": "GPL-3.0-or-later",
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Sascha Nitsch",
 | 
			
		||||
            "email": "grumpydevelop@contentnation.net"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "phan/phan": "^5.4"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								config.ini
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								config.ini
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
[database]
 | 
			
		||||
host = '127.0.0.1'
 | 
			
		||||
username = 'federator'
 | 
			
		||||
password = '*change*me*'
 | 
			
		||||
database = 'federator'
 | 
			
		||||
 | 
			
		||||
[templates]
 | 
			
		||||
path = '../templates/'
 | 
			
		||||
compiledir = '../cache'
 | 
			
		||||
 | 
			
		||||
[plugins]
 | 
			
		||||
rediscache = '../plugins/rediscache.php'
 | 
			
		||||
dummy = '../plugins/dummyconnector.php'
 | 
			
		||||
							
								
								
									
										22
									
								
								htdocs/api.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								htdocs/api.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
if (! array_key_exists('_call', $_REQUEST)) {
 | 
			
		||||
    http_response_code(404);
 | 
			
		||||
    exit();
 | 
			
		||||
}
 | 
			
		||||
date_default_timezone_set("Europe/Berlin");
 | 
			
		||||
spl_autoload_register(function ($className) {
 | 
			
		||||
    // strip Federator from class path
 | 
			
		||||
    $className = str_replace('Federator\\', '', $className);
 | 
			
		||||
    include '../php/' . str_replace("\\", "/", strtolower($className)) . '.php';
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/// main instance
 | 
			
		||||
$contentnation = new \Federator\Api();
 | 
			
		||||
$contentnation->run();
 | 
			
		||||
							
								
								
									
										252
									
								
								php/api.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								php/api.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,252 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
 namespace Federator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * main API class
 | 
			
		||||
 */
 | 
			
		||||
class Api extends Main
 | 
			
		||||
{
 | 
			
		||||
    /** @var string called path */
 | 
			
		||||
    private $path;
 | 
			
		||||
 | 
			
		||||
    /** @var array<string> path elements for the API call */
 | 
			
		||||
    private $paths;
 | 
			
		||||
 | 
			
		||||
    /** @var Data\User current user */
 | 
			
		||||
    private $user;
 | 
			
		||||
 | 
			
		||||
    /** @var int cache time default to 0 */
 | 
			
		||||
    private $cacheTime = 0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->smarty = null;
 | 
			
		||||
        $this->contentType = "application/json";
 | 
			
		||||
        Main::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set path
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $call
 | 
			
		||||
     *          path of called function
 | 
			
		||||
     */
 | 
			
		||||
    public function setPath(string $call) : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->path = $call;
 | 
			
		||||
        while ($this->path[0] === '/') {
 | 
			
		||||
            $this->path = substr($this->path, 1);
 | 
			
		||||
        }
 | 
			
		||||
        $this->paths = explode("/", $this->path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * main API function
 | 
			
		||||
     */
 | 
			
		||||
    public function run() : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->setPath($_REQUEST["_call"]);
 | 
			
		||||
        $this->openDatabase();
 | 
			
		||||
        $this->loadPlugins();
 | 
			
		||||
        $retval = "";
 | 
			
		||||
        /** @var \Api\Api */
 | 
			
		||||
        $handler = null;
 | 
			
		||||
        if (!array_key_exists('HTTP_X_SESSION', $_SERVER) || !array_key_exists('HTTP_X_PROFILE', $_SERVER)) {
 | 
			
		||||
            http_response_code(403);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if ($this->connector === null) {
 | 
			
		||||
            http_response_code(500);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        $this->user = DIO\User::getUserBySession(
 | 
			
		||||
            $this->dbh,
 | 
			
		||||
            $_SERVER['HTTP_X_SESSION'],
 | 
			
		||||
            $_SERVER['HTTP_X_PROFILE'],
 | 
			
		||||
            $this->connector,
 | 
			
		||||
            $this->cache
 | 
			
		||||
        );
 | 
			
		||||
        if ($this->user === false) {
 | 
			
		||||
            http_response_code(403);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        switch ($this->path[0]) {
 | 
			
		||||
            case 'v':
 | 
			
		||||
                if ($this->paths[0] === "v1") {
 | 
			
		||||
                    switch ($this->paths[1]) {
 | 
			
		||||
                        case 'dummy':
 | 
			
		||||
                            $handler = new Api\V1\Dummy($this);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        $printresponse = true;
 | 
			
		||||
        if ($handler !== null) {
 | 
			
		||||
            try {
 | 
			
		||||
                $printresponse = $handler->exec($this->paths);
 | 
			
		||||
                if ($printresponse) {
 | 
			
		||||
                    $retval = $handler->toJson();
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Exceptions\Exception $e) {
 | 
			
		||||
                $this->setResponseCode($e->getRetCode());
 | 
			
		||||
                $retval = json_encode(array(
 | 
			
		||||
                    "error" => $e->getMessage()
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->responseCode = 404;
 | 
			
		||||
        }
 | 
			
		||||
        if (sizeof($this->headers) != 0) {
 | 
			
		||||
            foreach ($this->headers as $name => $value) {
 | 
			
		||||
                header($name . ': ' . $value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if ($printresponse) {
 | 
			
		||||
            if ($this->redirect !== null) {
 | 
			
		||||
                header("Location: $this->redirect");
 | 
			
		||||
            }
 | 
			
		||||
            if ($this->responseCode != 200) {
 | 
			
		||||
                http_response_code($this->responseCode);
 | 
			
		||||
            }
 | 
			
		||||
            if ($this->responseCode != 404) {
 | 
			
		||||
                header("Content-type: " . $this->contentType);
 | 
			
		||||
                header("Access-Control-Allow-Origin: *");
 | 
			
		||||
            }
 | 
			
		||||
            if ($this->cacheTime == 0) {
 | 
			
		||||
                header("Cache-Control: no-cache, no-store, must-revalidate");
 | 
			
		||||
                header("Pragma: no-cache");
 | 
			
		||||
                header("Expires: 0");
 | 
			
		||||
            } else {
 | 
			
		||||
                $ts = gmdate("D, d M Y H:i:s", time() + $this->cacheTime) . " GMT";
 | 
			
		||||
                header("Expires: $ts");
 | 
			
		||||
                header("Pragma: cache");
 | 
			
		||||
                header("Cache-Control: max-age=" . $this->cacheTime);
 | 
			
		||||
            }
 | 
			
		||||
            echo $retval;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!headers_sent()) {
 | 
			
		||||
                header("Content-type: " . $this->contentType);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check if the current user has the given permission
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|string[] $permission
 | 
			
		||||
     *          permission(s) to check for
 | 
			
		||||
     * @param string $exception Exception Type
 | 
			
		||||
     * @param string $message optional message
 | 
			
		||||
     * @throws \Exceptions\PermissionDenied
 | 
			
		||||
     */
 | 
			
		||||
    public function checkPermission($permission, $exception = "\Exceptions\PermissionDenied", $message = null) : void
 | 
			
		||||
    {
 | 
			
		||||
        // generic check first
 | 
			
		||||
        if ($this->user->id == 0) {
 | 
			
		||||
            throw new Exceptions\PermissionDenied();
 | 
			
		||||
        }
 | 
			
		||||
        if (!is_array($permission)) {
 | 
			
		||||
            $permission = array(
 | 
			
		||||
                $permission
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // LoggedIn is handled above
 | 
			
		||||
        foreach ($permission as $p) {
 | 
			
		||||
            if ($this->user->hasPermission($p)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        throw new $exception($message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * remove unwanted elements from html input
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_input
 | 
			
		||||
     *          input to strip
 | 
			
		||||
     * @return string stripped input
 | 
			
		||||
     */
 | 
			
		||||
    public static function stripHTML(string $_input) : string
 | 
			
		||||
    {
 | 
			
		||||
        $out = preg_replace('/<(script[^>]*)>/i', '<${1}>', $_input);
 | 
			
		||||
        $out = preg_replace('/<\/(script)>/i', '</${1};>', $out);
 | 
			
		||||
        return $out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * is given parameter in POST data
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_key
 | 
			
		||||
     *          parameter to check
 | 
			
		||||
     * @return bool true if in
 | 
			
		||||
     */
 | 
			
		||||
    public static function hasPost(string $_key) : bool
 | 
			
		||||
    {
 | 
			
		||||
        return array_key_exists($_key, $_POST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SQL escape given POST parameter
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $key
 | 
			
		||||
     *          key to escape
 | 
			
		||||
     * @param boolean $int
 | 
			
		||||
     *          is parameter an int
 | 
			
		||||
     * @return int|string
 | 
			
		||||
     */
 | 
			
		||||
    public function escapePost(string $key, $int = false)
 | 
			
		||||
    {
 | 
			
		||||
        if (! array_key_exists($key, $_POST)) {
 | 
			
		||||
            return $int ? 0 : "";
 | 
			
		||||
        }
 | 
			
		||||
        if ($int === true) {
 | 
			
		||||
            return intval($_POST[$key]);
 | 
			
		||||
        }
 | 
			
		||||
        $ret = $this->dbh->escape_string($this->stripHTML($_POST[$key]));
 | 
			
		||||
        if ($ret === false) {
 | 
			
		||||
            return $int ? 0 : "";
 | 
			
		||||
        }
 | 
			
		||||
        return $ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * update $data with POST info using optional alias $altName
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $name
 | 
			
		||||
     *          parameter name
 | 
			
		||||
     * @param array<string,mixed> $data
 | 
			
		||||
     *          array to update
 | 
			
		||||
     * @param bool $int
 | 
			
		||||
     *          is data an integer
 | 
			
		||||
     * @param string $altName
 | 
			
		||||
     *          optional alternative name in POST
 | 
			
		||||
     */
 | 
			
		||||
    public function updateString(string $name, array &$data, bool $int = false, string $altName = "") : void
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->hasPost($altName ?: $name)) {
 | 
			
		||||
            $content = $this->escapePost($altName ?: $name, $int);
 | 
			
		||||
            $data[$name] = $content;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set cache time
 | 
			
		||||
     *
 | 
			
		||||
     * @param int $time time in seconds
 | 
			
		||||
     */
 | 
			
		||||
    public function setCacheTime(int $time) : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->cacheTime = $time;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								php/api/v1.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								php/api/v1.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator\Api;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * API interface
 | 
			
		||||
 */
 | 
			
		||||
interface V1
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * run given url path
 | 
			
		||||
     * @param string[] $paths path array split by /
 | 
			
		||||
     * @return bool true on success
 | 
			
		||||
     */
 | 
			
		||||
    public function exec($paths) : bool;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get internal represenation as json string
 | 
			
		||||
     * @return string json string or html
 | 
			
		||||
     */
 | 
			
		||||
    public function toJson() : string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								php/api/v1/dummy.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								php/api/v1/dummy.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator\Api\V1;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dummy api class for functional poc
 | 
			
		||||
 */
 | 
			
		||||
class Dummy implements \Federator\Api\V1
 | 
			
		||||
{
 | 
			
		||||
    /** @var \Main $main main instance */
 | 
			
		||||
    private $main;
 | 
			
		||||
 | 
			
		||||
    /** @var Array<string, string> $message internal message to output */
 | 
			
		||||
    private $message = [];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     * @param \Main $main main instance
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(\Federator\Main $main)
 | 
			
		||||
    {
 | 
			
		||||
        $this->main = $main;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * run given url path
 | 
			
		||||
     * @param string[] $paths path array split by /
 | 
			
		||||
     * @return bool true on success
 | 
			
		||||
     */
 | 
			
		||||
    public function exec($paths) : bool
 | 
			
		||||
    {
 | 
			
		||||
        $method = $_SERVER["REQUEST_METHOD"];
 | 
			
		||||
        switch ($method) {
 | 
			
		||||
            case 'GET':
 | 
			
		||||
                switch (sizeof($paths)) {
 | 
			
		||||
                    case 3:
 | 
			
		||||
                        if ($paths[2] === 'moo') {
 | 
			
		||||
                            return $this->getDummy();
 | 
			
		||||
                        }
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case 'POST':
 | 
			
		||||
                switch (sizeof($paths)) {
 | 
			
		||||
                    case 3:
 | 
			
		||||
                        if ($paths[2] === 'moo') {
 | 
			
		||||
                            return $this->postDummy();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
        $this->main->setResponseCode(404);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get function for "/v1/dummy/moo"
 | 
			
		||||
     */
 | 
			
		||||
    public function getDummy(): bool
 | 
			
		||||
    {
 | 
			
		||||
        $this->message = [
 | 
			
		||||
            'r1' => '             (__)       ',
 | 
			
		||||
            'r2' => '      `------(oo)       ',
 | 
			
		||||
            'r3' => '       || __ (__)       ',
 | 
			
		||||
            'r4' => '       ||w  ||          ',
 | 
			
		||||
            'r5' => '                        '
 | 
			
		||||
        ];
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * post function for /v1/dummy/moo"
 | 
			
		||||
     */
 | 
			
		||||
    public function postDummy() : bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->getDummy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get internal represenation as json string
 | 
			
		||||
     * @return string json string
 | 
			
		||||
     */
 | 
			
		||||
    public function toJson() : string
 | 
			
		||||
    {
 | 
			
		||||
        return json_encode($this->message, JSON_PRETTY_PRINT) . "\n";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								php/connector/connector.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								php/connector/connector.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator\Connector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * base class for remote authentication
 | 
			
		||||
 */
 | 
			
		||||
interface Connector
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     * @param string $_session session id
 | 
			
		||||
     * @param string $_user user/profile name
 | 
			
		||||
     * @return \Federator\Data\User | null
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserBySession(string $_session, string $_user);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								php/data/user.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								php/data/user.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator\Data;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * storage class for user attributes
 | 
			
		||||
 */
 | 
			
		||||
class User
 | 
			
		||||
{
 | 
			
		||||
    /** @var string user id */
 | 
			
		||||
    public $id;
 | 
			
		||||
 | 
			
		||||
    /* @var string user language */
 | 
			
		||||
    //public $lang;
 | 
			
		||||
 | 
			
		||||
    /** @var array<string> user permissions */
 | 
			
		||||
    public $permissions = [];
 | 
			
		||||
 | 
			
		||||
    /** @var string session id */
 | 
			
		||||
    public $session;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check if use has asked permission
 | 
			
		||||
     * @param string $p @unused-param
 | 
			
		||||
     *        permission to check
 | 
			
		||||
    *
 | 
			
		||||
     * @return bool true if user has permission, false if not
 | 
			
		||||
     */
 | 
			
		||||
    public function hasPermission(string $p)
 | 
			
		||||
    {
 | 
			
		||||
        return in_array($p, $this->permissions);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								php/dio/user.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								php/dio/user.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator\DIO;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * IO functions related to users
 | 
			
		||||
 */
 | 
			
		||||
class User
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * extend the given user with internal data
 | 
			
		||||
     * @param \mysqli $dbh database  handle @unused-param
 | 
			
		||||
     * @param \Federator\Data\User $user user to extend @unused-param
 | 
			
		||||
     */
 | 
			
		||||
    protected static function extendUser(\mysqli $dbh, \Federator\Data\User $user) : void
 | 
			
		||||
    {
 | 
			
		||||
        // do nothing for now
 | 
			
		||||
        // TODO: if a new user, create own database entry with additionally needed info
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get User by session id
 | 
			
		||||
     *
 | 
			
		||||
     * @param \mysqli $dbh
 | 
			
		||||
     *          database handle
 | 
			
		||||
     * @param string $_session
 | 
			
		||||
     *          session
 | 
			
		||||
     * @param string $_user
 | 
			
		||||
     *          user/profile name
 | 
			
		||||
     * @param \Connector\Connector? $connector @unused-param
 | 
			
		||||
     *          connector to fetch use with
 | 
			
		||||
     * @param \Cache\Cache? $cache
 | 
			
		||||
     *          optional caching service
 | 
			
		||||
     * @return \Data\User|bool
 | 
			
		||||
     */
 | 
			
		||||
    public static function getUserBySession($dbh, $_session, $_user, $connector, $cache)
 | 
			
		||||
    {
 | 
			
		||||
        $user = false;
 | 
			
		||||
        if ($cache) {
 | 
			
		||||
            $user = $cache->getRemoteUserBySession($_session, $_user);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // ask connector for user-id
 | 
			
		||||
        $user = $connector->getRemoteUserBySession($_session, $_user);
 | 
			
		||||
        if ($user === false) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if ($cache) {
 | 
			
		||||
            $cache->saveRemoteUserBySession($_session, $_user, $user);
 | 
			
		||||
        }
 | 
			
		||||
        self::extendUser($dbh, $user);
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								php/exceptions/exception.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								php/exceptions/exception.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * base class for our Exceptions
 | 
			
		||||
 */
 | 
			
		||||
class Exception extends \Error
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * get matching HTTP response code
 | 
			
		||||
     *
 | 
			
		||||
     * @return int number HTTP response code
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 500;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								php/exceptions/filenotfound.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								php/exceptions/filenotfound.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * File not found exceptions
 | 
			
		||||
 */
 | 
			
		||||
class FileNotFound extends Exception
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     * @param ?string $message optional error message
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($message = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->message = ($message === null) ? "filenotfound" : $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     * @see \Exceptions\Exception::getRetCode()
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 404;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								php/exceptions/invalidargument.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								php/exceptions/invalidargument.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invalid Argument Exception
 | 
			
		||||
 */
 | 
			
		||||
class InvalidArgument extends Exception
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     * @param ?string $message optional error message
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($message = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->message = ($message === null) ? "invalidargument" : $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     * @see \Exceptions\Exception::getRetCode()
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 400;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								php/exceptions/permissiondenied.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								php/exceptions/permissiondenied.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Permission denied exception
 | 
			
		||||
 */
 | 
			
		||||
class PermissionDenied extends Exception
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     *
 | 
			
		||||
     * @param ?string $message
 | 
			
		||||
     *          error message
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($message = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->message = ($message === null) ? "permissiondenied" : $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * {@inheritdoc}
 | 
			
		||||
     * @see \Exceptions\Exception::getRetCode()
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 403;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								php/exceptions/servererror.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								php/exceptions/servererror.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Server Error Exception
 | 
			
		||||
 */
 | 
			
		||||
class ServerError extends Exception
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     * @param ?string $message optional error message
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($message = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->message = ($message === null) ? "servererror" : $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     * @see \Exceptions\Exception::getRetCode()
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 500;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								php/exceptions/unauthorized.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								php/exceptions/unauthorized.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Federator\Exceptions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unauthorized Exception
 | 
			
		||||
 */
 | 
			
		||||
class Unauthorized extends Exception
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     * @see \Exceptions\Exception::getRetCode()
 | 
			
		||||
     */
 | 
			
		||||
    public function getRetCode() : int
 | 
			
		||||
    {
 | 
			
		||||
        return 401;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										296
									
								
								php/language.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								php/language.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,296 @@
 | 
			
		|||
-<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 * @author Author: Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 */
 | 
			
		||||
require_once '../vendor/autoload.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Language abstraction class
 | 
			
		||||
 * @author Sascha Nitsch
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class Language {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * list of valid languages
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  private $validLanguages = array(
 | 
			
		||||
    "de" => true,
 | 
			
		||||
    "en" => true,
 | 
			
		||||
    "xy" => true
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * language to use
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  private $uselang;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * actual language data
 | 
			
		||||
   * @var array<string,array<string,string>>
 | 
			
		||||
   */
 | 
			
		||||
  private $lang = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * constructor that tries to autodetect language
 | 
			
		||||
   *
 | 
			
		||||
   * @param ?string $uselang
 | 
			
		||||
   *          use this language instead of autodetection, set to null if no preference
 | 
			
		||||
   */
 | 
			
		||||
  function __construct($uselang = null) {
 | 
			
		||||
    $this->lang = Array();
 | 
			
		||||
    if ($uselang !== null) {
 | 
			
		||||
      if (! array_key_exists($uselang, $this->validLanguages)) {
 | 
			
		||||
        $uselang = null;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if ($uselang === null && array_key_exists('_lang', $_REQUEST)) {
 | 
			
		||||
      $language = $_REQUEST['_lang'];
 | 
			
		||||
      if (array_key_exists($language, $this->validLanguages)) {
 | 
			
		||||
        $uselang = $language;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if ($uselang === null && array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
 | 
			
		||||
      $matches = array();
 | 
			
		||||
      if (preg_match("/^(\S\S)\-/",$_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches) == 1) {
 | 
			
		||||
        $language = $matches[1];
 | 
			
		||||
        if (array_key_exists($language, $this->validLanguages)) {
 | 
			
		||||
          $uselang = $language;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if ($uselang === null) {
 | 
			
		||||
      $uselang = 'de';
 | 
			
		||||
    }
 | 
			
		||||
    $this->uselang = $uselang;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * print translation of given group and id, optionally using variables
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $group
 | 
			
		||||
   *          group name
 | 
			
		||||
   * @param string $key
 | 
			
		||||
   *          string name
 | 
			
		||||
   * @param array<mixed> $values
 | 
			
		||||
   *          optional values to replace
 | 
			
		||||
   * @return string translated string
 | 
			
		||||
   */
 | 
			
		||||
  function printlang($group, $key, array $values = array()) {
 | 
			
		||||
    if ($this->uselang === 'xy') {
 | 
			
		||||
     return "$group:$key";
 | 
			
		||||
    }
 | 
			
		||||
    if (! isset($this->lang[$group])) {
 | 
			
		||||
      $l = [];
 | 
			
		||||
      $root = $_SERVER['DOCUMENT_ROOT'];
 | 
			
		||||
      if ($root === '') $root = '.';
 | 
			
		||||
      if (@file_exists($root . '/../lang/' . $this->uselang . "/$group.inc")) {
 | 
			
		||||
        require ($root . '/../lang/' . $this->uselang . "/$group.inc");
 | 
			
		||||
        $this->lang[$group] = $l;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (array_key_exists($group, $this->lang) && array_key_exists($key, $this->lang[$group])) {
 | 
			
		||||
      $string = $this->lang[$group][$key];
 | 
			
		||||
      for ($i = 0; $i < 9; $i ++) {
 | 
			
		||||
        if (isset($values[$i])) {
 | 
			
		||||
          $string = str_replace("\$$i", $values[$i], $string);
 | 
			
		||||
        } else {
 | 
			
		||||
          $string = str_replace("\$$i", "", $string);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return $string;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $basedir = $_SERVER['DOCUMENT_ROOT'] . '/../';
 | 
			
		||||
    $fh = @fopen("$basedir/logs/missingtrans.txt", 'a');
 | 
			
		||||
    if ($fh !== false) {
 | 
			
		||||
      fwrite($fh, $this->uselang.":$group:$key\n");
 | 
			
		||||
      fclose($fh);
 | 
			
		||||
    }
 | 
			
		||||
    return ">>$group:$key<<";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * get keys (valid ids) of a named group
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $group
 | 
			
		||||
   *          group name to fetch keys
 | 
			
		||||
   * @return array<string> list of keys
 | 
			
		||||
   */
 | 
			
		||||
  function getKeys(string $group) {
 | 
			
		||||
    if (! isset($this->lang[$group])) {
 | 
			
		||||
      $l = [];
 | 
			
		||||
      require_once ($_SERVER['DOCUMENT_ROOT'] . '/../lang/' . $this->uselang . "/$group.inc");
 | 
			
		||||
      $this->lang[$group] = $l;
 | 
			
		||||
    }
 | 
			
		||||
    return array_keys($this->lang[$group]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * return current used language
 | 
			
		||||
   *
 | 
			
		||||
   * @return string current language
 | 
			
		||||
   */
 | 
			
		||||
  function getLang() {
 | 
			
		||||
    return $this->uselang;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * guess langauge of text
 | 
			
		||||
   * @param string $text
 | 
			
		||||
   * @param string $default
 | 
			
		||||
   * @return string detected language
 | 
			
		||||
   */
 | 
			
		||||
  static function guessLanguage(string $text, string $default, bool $debug = false) {
 | 
			
		||||
    $supported_languages = array(
 | 
			
		||||
      'en',
 | 
			
		||||
      'de',
 | 
			
		||||
    );
 | 
			
		||||
    $wordList = [];
 | 
			
		||||
    // German word list
 | 
			
		||||
    // from http://wortschatz.uni-leipzig.de/Papers/top100de.txt
 | 
			
		||||
    $wordList['de'] = array (
 | 
			
		||||
      'die', 'der', 'und', /*'in',*/ 'zu', 'den', 'das', 'nicht', 'von', 'sie',
 | 
			
		||||
      'ist', 'des', 'sich', 'mit', 'dem', 'dass', 'er', 'es', 'ein', 'ich',
 | 
			
		||||
      'auf', 'so', 'eine', 'auch', 'als', 'an', 'nach', 'wie', 'im', 'für',
 | 
			
		||||
      'man', 'aber', 'aus', 'durch', 'wenn', 'nur', 'war', 'noch', 'werden',
 | 
			
		||||
      'bei', 'hat', 'wir', 'was', 'wird', 'sein', 'einen', 'welche', 'sind',
 | 
			
		||||
      'oder', 'zur', 'um', 'haben', 'einer', 'mir', 'über', 'ihm', 'diese',
 | 
			
		||||
      'einem', 'ihr', 'uns', 'da', 'zum', 'kann', 'doch', 'vor', 'dieser',
 | 
			
		||||
      'mich', 'ihn', 'du', 'hatte', 'seine', 'mehr', 'am', 'denn', 'nun',
 | 
			
		||||
      'unter', 'sehr', 'selbst', 'schon', 'hier', 'bis', 'habe', 'ihre',
 | 
			
		||||
      'dann', 'ihnen', 'seiner', 'alle', 'wieder', 'meine', 'Zeit', 'gegen',
 | 
			
		||||
      'vom', 'ganz', 'einzelnen', 'wo', 'muss', 'ohne', 'eines', 'können',
 | 
			
		||||
      'sei', 'geschrieben', 'instanzen', 'deutsch','aktualisierung', 'registrierung'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // English word list
 | 
			
		||||
    // from http://en.wikipedia.org/wiki/Most_common_words_in_English
 | 
			
		||||
    $wordList['en'] = array ('the', 'be', 'to', 'of', 'and', 'a', /*'in',*/
 | 
			
		||||
      'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he',
 | 
			
		||||
      'as', 'you', 'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they',
 | 
			
		||||
      'we', 'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all',
 | 
			
		||||
      'would', 'there', 'their', 'what', 'so', 'up', 'out', 'if', 'about'
 | 
			
		||||
    );
 | 
			
		||||
    // French word list
 | 
			
		||||
    // from https://1000mostcommonwords.com/1000-most-common-french-words/
 | 
			
		||||
    /*$wordList['fr'] = array ('comme', 'que',  'tait',  'pour',  'sur',  'sont',  'avec',
 | 
			
		||||
      'tre',  'un',  'ce',  'par',  'mais',  'que',  'est',
 | 
			
		||||
      'il',  'eu',  'la', 'et', 'dans');*/
 | 
			
		||||
 | 
			
		||||
    // Spanish word list
 | 
			
		||||
    // from https://spanishforyourjob.com/commonwords/
 | 
			
		||||
    /*$wordList['es'] = array ('que', 'no', 'a', 'la', 'el', 'es', 'y',
 | 
			
		||||
      'en', 'lo', 'un', 'por', 'qu', 'si', 'una',
 | 
			
		||||
      'los', 'con', 'para', 'est', 'eso', 'las');*/
 | 
			
		||||
 | 
			
		||||
    // clean out the input string - note we don't have any non-ASCII
 | 
			
		||||
    // characters in the word lists... change this if it is not the
 | 
			
		||||
    // case in your language wordlists!
 | 
			
		||||
    $txt = strip_tags($text);
 | 
			
		||||
    $txt = preg_replace("/[^A-Za-z:\\/\\.]+/", ' ', $txt);
 | 
			
		||||
    if ($debug) echo "text: '$txt'\n";
 | 
			
		||||
    $counter = [];
 | 
			
		||||
    // count the occurrences of the most frequent words
 | 
			
		||||
    foreach ($supported_languages as $language) {
 | 
			
		||||
      $counter[$language]=0;
 | 
			
		||||
    }
 | 
			
		||||
    foreach ($supported_languages as $language) {
 | 
			
		||||
      for ($i = 0; $i < sizeof($wordList[$language]); ++$i) {
 | 
			
		||||
        $count = substr_count($txt, ' ' .$wordList[$language][$i] . ' ');
 | 
			
		||||
        if ($debug && $count > 0) {
 | 
			
		||||
          echo $language . " " . $wordList[$language][$i] . " => $count\n";
 | 
			
		||||
        }
 | 
			
		||||
        $counter[$language] += $count;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if ($debug)
 | 
			
		||||
      print_r($counter);
 | 
			
		||||
    // get max counter value
 | 
			
		||||
    $max = max($counter);
 | 
			
		||||
    $maxs = array_keys($counter, $max);
 | 
			
		||||
    // if there are two winners - fall back to default!
 | 
			
		||||
    if (count($maxs) == 1) {
 | 
			
		||||
      $winner = $maxs[0];
 | 
			
		||||
      $second = 0;
 | 
			
		||||
      // get runner-up (second place)
 | 
			
		||||
      foreach ($supported_languages as $language) {
 | 
			
		||||
        if ($language !== $winner) {
 | 
			
		||||
          if ($counter[$language]>$second) {
 | 
			
		||||
            $second = $counter[$language];
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // apply arbitrary threshold of 50%
 | 
			
		||||
      if (($second / $max) < 0.5) {
 | 
			
		||||
        return $winner;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $default;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * function called from smarty templates to print language translation
 | 
			
		||||
 *
 | 
			
		||||
 * @param array<string,mixed> $params
 | 
			
		||||
 *          smarty params, used are 'group', 'txt' and optionally 'var'
 | 
			
		||||
 * @param \Smarty\Template $template
 | 
			
		||||
 *          template instance
 | 
			
		||||
 * @return string translated text
 | 
			
		||||
 */
 | 
			
		||||
function smarty_function_printlang($params, $template) : string {
 | 
			
		||||
  $lang = $template->getTemplateVars("language");
 | 
			
		||||
  <<<'PHAN'
 | 
			
		||||
    @phan-var \Language $lang
 | 
			
		||||
    PHAN;
 | 
			
		||||
  $forcelang = array_key_exists('lang', $params) ? $params['lang'] : null;
 | 
			
		||||
  if ($forcelang !== null) {
 | 
			
		||||
    $lang = new \Language($forcelang);
 | 
			
		||||
  }
 | 
			
		||||
  if (isset($params['var'])) {
 | 
			
		||||
    return $lang->printlang($params['group'], $params['key'], $params['var']);
 | 
			
		||||
  } else {
 | 
			
		||||
    return $lang->printlang($params['group'], $params['key']);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * function called from smarty templates to set language translation as JS string
 | 
			
		||||
 *
 | 
			
		||||
 * @param array<string, mixed> $params
 | 
			
		||||
 *          smarty params, used are 'group', 'txt' and optionally 'var'
 | 
			
		||||
 * @param \Smarty\Template $template
 | 
			
		||||
 *          template instance
 | 
			
		||||
 * @return string translated text as JS line
 | 
			
		||||
 */
 | 
			
		||||
function smarty_function_printjslang($params, $template) : string {
 | 
			
		||||
  $lang = $template->getTemplateVars("language");
 | 
			
		||||
  $prefix = 'window.translations.' . $params['group'] . '.' . $params['key'] . ' = \'';
 | 
			
		||||
  $postfix = '\';';
 | 
			
		||||
  if (isset($params['var']))
 | 
			
		||||
    return $prefix . $lang->printlang($params['group'], $params['key'], $params['var']) . $postfix;
 | 
			
		||||
  else
 | 
			
		||||
    return $prefix . $lang->printlang($params['group'], $params['key']) . $postfix;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * print translation of given group and id, optionally using variables
 | 
			
		||||
 *
 | 
			
		||||
 * @param string $group
 | 
			
		||||
 *          group name
 | 
			
		||||
 * @param string $key
 | 
			
		||||
 *          string name
 | 
			
		||||
 * @param array<mixed> $values
 | 
			
		||||
 *          optional values to replace
 | 
			
		||||
 * @return string translated string
 | 
			
		||||
 */
 | 
			
		||||
function printlang(string  $group, string $key, array $values=array()) {
 | 
			
		||||
  global $contentnation;
 | 
			
		||||
  return $contentnation->translate(null, $group, $key, $values);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										178
									
								
								php/main.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								php/main.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,178 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 * @author Author: Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
 namespace Federator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base class for ContentNation and Api
 | 
			
		||||
 * @author Sascha Nitsch
 | 
			
		||||
 */
 | 
			
		||||
class Main
 | 
			
		||||
{
 | 
			
		||||
    /** @var Cache\Cache cache instance */
 | 
			
		||||
    protected $cache;
 | 
			
		||||
    /** @var array<string,mixed> current config */
 | 
			
		||||
    protected $config;
 | 
			
		||||
    /** @var Connector\Connector remote connector */
 | 
			
		||||
    protected $connector = null;
 | 
			
		||||
    /** @var string response content type */
 | 
			
		||||
    protected $contentType = "text/html";
 | 
			
		||||
    /** @var \Mysqli database instance */
 | 
			
		||||
    protected $dbh;
 | 
			
		||||
    /** @var array<string,string> extra headers */
 | 
			
		||||
    protected $headers = [];
 | 
			
		||||
    /** @var \Language languange instance */
 | 
			
		||||
    protected $lang = null;
 | 
			
		||||
    /** @var ?string redirect URL */
 | 
			
		||||
    protected $redirect = null;
 | 
			
		||||
    /** @var int response code */
 | 
			
		||||
    protected $responseCode = 200;
 | 
			
		||||
    /** @var \Smarty\Smarty|null smarty instance */
 | 
			
		||||
    protected $smarty;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->config = parse_ini_file('../config.ini', true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * do a remote call and return results
 | 
			
		||||
     * @param string $remoteURL remote URL
 | 
			
		||||
     * @param string[]|null $headers optional headers to send
 | 
			
		||||
     * @return array{string, mixed} response and status information
 | 
			
		||||
     */
 | 
			
		||||
    public static function getFromRemote(string $remoteURL, $headers)
 | 
			
		||||
    {
 | 
			
		||||
        $ch = curl_init();
 | 
			
		||||
        curl_setopt($ch, CURLOPT_URL, $remoteURL);
 | 
			
		||||
        curl_setopt($ch, CURLOPT_HEADER, 0);
 | 
			
		||||
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
			
		||||
        if ($headers !== null) {
 | 
			
		||||
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 | 
			
		||||
        }
 | 
			
		||||
        curl_setopt($ch, CURLOPT_VERBOSE, true);
 | 
			
		||||
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);
 | 
			
		||||
        $ret = curl_exec($ch);
 | 
			
		||||
        $info = curl_getinfo($ch);
 | 
			
		||||
        curl_close($ch);
 | 
			
		||||
        return [$ret, $info];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get config
 | 
			
		||||
     * @return Array<String, Mixed>
 | 
			
		||||
     */
 | 
			
		||||
    public function getConfig()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * load plugins
 | 
			
		||||
     */
 | 
			
		||||
    public function loadPlugins() : void
 | 
			
		||||
    {
 | 
			
		||||
        if (array_key_exists('plugins', $this->config)) {
 | 
			
		||||
            $plugins = $this->config['plugins'];
 | 
			
		||||
            foreach ($plugins as $name => $file) {
 | 
			
		||||
                require_once($file);
 | 
			
		||||
                $fktn = 'Federator\\' . $name . '_load';
 | 
			
		||||
                if (function_exists($fktn)) {
 | 
			
		||||
                    $fktn($this);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * open database
 | 
			
		||||
     */
 | 
			
		||||
    public function openDatabase() : void
 | 
			
		||||
    {
 | 
			
		||||
        $dbconf = $this->config["database"];
 | 
			
		||||
        $this->dbh = new \mysqli($dbconf['host'], $dbconf['username'], $dbconf['password'], $dbconf['database']);
 | 
			
		||||
        if ($this->dbh->connect_error !== null) {
 | 
			
		||||
            http_response_code(500);
 | 
			
		||||
            die('Database Connect Error');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set cache
 | 
			
		||||
     */
 | 
			
		||||
    public function setCache(Cache\Cache $cache) : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->cache = $cache;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set connector
 | 
			
		||||
     */
 | 
			
		||||
    public function setConnector(Connector\Connector $connector) : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->connector = $connector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set response code
 | 
			
		||||
     *
 | 
			
		||||
     * @param int $code
 | 
			
		||||
     *          new response code
 | 
			
		||||
     */
 | 
			
		||||
    public function setResponseCode(int $code) : void
 | 
			
		||||
    {
 | 
			
		||||
        $this->responseCode = $code;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * translate given group and key using given language
 | 
			
		||||
     *
 | 
			
		||||
     * @param ?string $lang
 | 
			
		||||
     *          language to use
 | 
			
		||||
     * @param string $group
 | 
			
		||||
     *          language group to use
 | 
			
		||||
     * @param string $key
 | 
			
		||||
     *          language key to use
 | 
			
		||||
     * @param mixed[] $parameters
 | 
			
		||||
     *          optional parameters
 | 
			
		||||
     * @return string translation
 | 
			
		||||
     */
 | 
			
		||||
    public function translate(?string $lang, string $group, string $key, array $parameters = array()) : string
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->lang === null) {
 | 
			
		||||
            $this->validLanguage($lang);
 | 
			
		||||
        }
 | 
			
		||||
        if ($this->lang !== null) {
 | 
			
		||||
            if ($this->lang->getLang() !== $lang) {
 | 
			
		||||
                $l = new \Language($lang);
 | 
			
		||||
                return $l->printlang($group, $key, $parameters);
 | 
			
		||||
            }
 | 
			
		||||
            return $this->lang->printlang($group, $key, $parameters);
 | 
			
		||||
        } else {
 | 
			
		||||
            return $key;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check if language is valid by loading it
 | 
			
		||||
     *
 | 
			
		||||
     * @param ?string $lang
 | 
			
		||||
     */
 | 
			
		||||
    public function validLanguage(?string $lang) : bool
 | 
			
		||||
    {
 | 
			
		||||
        $language = new \Language($lang);
 | 
			
		||||
        if ($language->getLang() === $lang) {
 | 
			
		||||
            $this->lang = $language;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								plugins/dummyconnector.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								plugins/dummyconnector.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 * @author Author: Sascha Nitsch (grumpydeveloper)
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
namespace Federator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dummy connector that always return the same permission
 | 
			
		||||
 */
 | 
			
		||||
class DummyConnector implements Connector\Connector
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     * @param string $_session session id
 | 
			
		||||
     * @param string $_user user or profile name
 | 
			
		||||
     * @return Data\User | false
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserBySession(string $_session, string $_user)
 | 
			
		||||
    {
 | 
			
		||||
        // validate $_session and $user
 | 
			
		||||
        $user = new Data\User();
 | 
			
		||||
        $user->id = $_user;
 | 
			
		||||
        $user->permissions = ['PUBLISH'];
 | 
			
		||||
        $user->session = $_session;
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dummy_load(Main $main)
 | 
			
		||||
{
 | 
			
		||||
    $dummy = new DummyConnector();
 | 
			
		||||
    $main->setConnector($dummy);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								progress.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								progress.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
# progress tracker
 | 
			
		||||
## done
 | 
			
		||||
 | 
			
		||||
## goals v1.0
 | 
			
		||||
primary goal is to connect ContentNation via ActivityPub again.
 | 
			
		||||
 | 
			
		||||
- [ ] browse the fediverse as a logged in user
 | 
			
		||||
- [ ] reply to posts
 | 
			
		||||
- [ ] like posts
 | 
			
		||||
- [ ] share posts
 | 
			
		||||
- [ ] comment on CN article via AP
 | 
			
		||||
- [ ] get notifications on AP if someone interacts with comment
 | 
			
		||||
 | 
			
		||||
## roadmap to v1.0
 | 
			
		||||
- [X] API framework
 | 
			
		||||
- [X] interfact to connect to existing service
 | 
			
		||||
- [ ] overlay to extend with needed info like private keys, urls, ...
 | 
			
		||||
- [ ] cache layer for users
 | 
			
		||||
- [ ] webfinger
 | 
			
		||||
- [ ] discovery endpoints
 | 
			
		||||
- [ ] ap outbox
 | 
			
		||||
- [ ] ap inbox
 | 
			
		||||
- [ ] support for AP profile in service
 | 
			
		||||
- [ ] support for article
 | 
			
		||||
- [ ] support for comment
 | 
			
		||||
- [ ] posting comments from ap to service
 | 
			
		||||
- [ ] callback from service to add new input
 | 
			
		||||
							
								
								
									
										1
									
								
								release.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								release.sh
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
git log | head -n1 | awk '{print "<?php\nglobal $version;\n$version=\"" $2 "\";\n"}' > php/version.php
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue