CMF Core

CMF Core 1.0.8

No permission to download

Yoskaldyr

Well-known member
Yoskaldyr submitted a new resource:

[CMF] Core - Dynamic extend any XenForo class

Description:
This plugin simplyfies and improves third-party plugin development in XenForo.

Features & pros:
  • Allows extending multiple XenForo classes with a single class without catching "PHP Fatal error: Cannot redeclare class" error message (now you can extend data writer groups or bbcodes with just one class instead of using multiple copies of the same thing but with different names).
  • It's possible to extend almost every class in XenForo, even static helper and...

Read more about this resource...
 
Yoskaldyr updated [CMF] Core with a new update entry:

CMF Core 1.0.0 Released

CMF Core Version 1.0.0 released.
Well tested on big forums with high activity of users.

Changes from RC:
+ safe auto update config.php on install/uninstall
+ early/eager loader feature is optional. Eager loader is needed to extend classes loaded before XenForo_Options. To enable eager loader init method must be called with parameter:
PHP:
CMF_Core_Autoloader::getProxy(true);

Read the rest of this update entry...
 
Last edited:
No, in the call stack XenForo_Input is a virtual proxy class extended from Sedo_ExtraHanzi_XenForo_Input and XFProxy_XenForo_Input (as copy from original XenForo_Input)
I continue the discussion here. What do you mean by "no"? There shouldn't have difference betwen the two?

Original class:
PHP:
  public static function cleanString($string)
   {
     var_dump("Original is: ".$string);
     // only cover the BMP as MySQL only supports that
     $string = preg_replace('/[\xF0-\xF7].../', '', $string);

     return strtr(strval($string), self::$_strClean);
   }

Extended class:
PHP:
  public static function cleanString($string)
   {
     var_dump("Extended is: ".$string);

     $string = parent::cleanString($string);

     return $string;
   }

One typing a post (reference text: "abc123def") and saving it, here the json output:
Code:
string(45) "Original is: 689564b38774b90b4191752c11df3311"
string(29) "Original is: <p>abc123def</p>"
string(91) "Original is: http://localhost/xenforo/index.php?threads/test-center-ezfze-center.847/page-3"
string(22) "Extended is: abc123def"
string(22) "Original is: abc123def"
string(22) "Extended is: abc123def"
string(22) "Original is: abc123def"
string(13) "Original is: "

As you can see, data processed by both functions are not the same.

Now let's modify the extended class with this code:
PHP:
  public static function cleanString($string)
   {
     var_dump("Extended is: ".$string);
     $extraHanzi = new Sedo_ExtraHanzi_Helper_Characters();

     $string = $extraHanzi->encodeExtraHanzi($string);
     $string = parent::cleanString($string); //$string = XFProxy_XenForo_Input::cleanString($string);
     $string = $extraHanzi->decodeExtraHanzi($string);

     return $string;
   }

And let's us as reference text: abc{U+21075}def; {U+21075} being the real unicode character (ref). Here's the output:
PHP:
string(45) "Original is: 689564b38774b90b4191752c11df3311"
string(30) "Original is: <p>abc{U+21075}def</p>"
string(91) "Original is: http://localhost/xenforo/index.php?threads/test-center-ezfze-center.847/page-3"
string(19) "Extended is: abcdef"
string(19) "Original is: abcdef"
string(19) "Extended is: abcdef"
string(19) "Original is: abcdef"

As you can see, there's not way to target the unicode character in the extended class.

So back to my question, is this behaviour normal ?
 
So back to my question, is this behaviour normal ?
Yes this behavior is normal and class extender works as described in documentation.
Almost any base class can be extended by add-on, but you must remember about visibility of 'self::$static_var/method()' of not instantiated classes extended from other classes in php.
So, you can extend base xenforo static class, but you cannot change var/method visibility for 'self::' calls in php. So you must copy/paste to extended class almost any static methods from original class use direct link to it (XFProxy_XenForo_Input::$staticvar/staticmethod() etc...)

Explanation based on your code, as cleanString static method calls from many places in XenForo_Input:
  • If cleanString called as XenForo_Input::cleanString from the outside of XenForo_Input - extended method will be called
  • If cleanString called as self::cleanString from static method of not instantiated XenForo_Input - base method will be called
  • If cleanString called as self::cleanString from non static method of XenForo_Input or from any method of XenForo_Input instance - extended method will be called
 
@Yoskaldyr
Thanks a lot for your explanations.

So if I understood correctly the static " _doClean" function of the XenForo_Input can't be directly extended since it's only called from this class UNLESS all its callers are copied in the extended class as well. This means everytime XenForo publishes an update, the extended code must be checked and updated as well.

Edit: I've got another question ; if coders:
  1. Use a common "Proxy" directory in your CMF library
  2. Copy in it (keeping the directory structure) the XenForo class they need to extend changing the class name to CMF_Proxy_XenForoDirectory_MyXenForoClass
  3. Then use your event listener "load_class_proxy_class" to extend the proxy class (exact copy from the XenForo class)
This time, since the proxy class could be extended without the issue described above? (I will check later if needed) The only thing that would remain would be to updated the proxy class when XenForo published an update.

Edit 2: nope, the result is the original has been replaced by the proxy (as intended) but the class that extends the proxy class using the event "load_class_proxy_class" is behaving the same way with a the former pattern (proxy that directly extends the original class). So the only solution is to copy a lot of XenForo code in the proxy class which rises a copyright issue and a maintenance issue (for updates).
 
Last edited:
Edit 2: nope, the result is the original has been replaced by the proxy (as intended) but the class that extends the proxy class using the event "load_class_proxy_class" is behaving the same way with a the former pattern (proxy that directly extends the original class). So the only solution is to copy a lot of XenForo code in the proxy class which rises a copyright issue and a maintenance issue (for updates).
Yes, solution for extending static methods in XenForo_Input is a copy/paste original code (not good, but I hope in XF 2.x late static binding feature will be used)
 
@Yoskaldyr
this is my conf at the moment (I have uninstall Xon's addon)

Code:
# Centmin Mod Getting Started Guide
# must read http://centminmod.com/getstarted.html
# For SPDY SSL Setup
# read http://centminmod.com/nginx_configure_https_ssl_spdy.html

# redirect from www to non-www  forced SSL
# uncomment, save file and restart Nginx to enable
# if unsure use return 302 before using return 301
server {
   server_name pijanitvor.com www.pijanitvor.com;
    return 301 https://www.$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name pijanitvor.com www.pijanitvor.com;

  ssl_dhparam /usr/local/nginx/conf/ssl/pijanitvor.com/dhparam.pem;
  ssl_certificate      /usr/local/nginx/conf/ssl/pijanitvor.com/ssl-unified.crt;
  ssl_certificate_key  /usr/local/nginx/conf/ssl/pijanitvor.com/pijanitvor.com.key;
  include /usr/local/nginx/conf/ssl_include.conf;

  # mozilla recommended
  ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!CAMELLIA:!DES-CBC3-SHA;
  ssl_prefer_server_ciphers   on;
  ####add_header Alternate-Protocol  443:npn-spdy/3;
  #add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
  #add_header  X-Content-Type-Options "nosniff";
  #add_header X-Frame-Options DENY;
  ####spdy_headers_comp 5;
  ssl_buffer_size 1400;
  ssl_session_tickets on;
 
  #enable ocsp stapling
  resolver 8.8.8.8 8.8.4.4 valid=10m;
  resolver_timeout 10s;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /usr/local/nginx/conf/ssl/pijanitvor.com/ssl-trusted.crt; 

# ngx_pagespeed & ngx_pagespeed handler
#include /usr/local/nginx/conf/pagespeed.conf;
#include /usr/local/nginx/conf/pagespeedhandler.conf;
#include /usr/local/nginx/conf/pagespeedstatslog.conf;

  # limit_conn limit_per_ip 16;
  # ssi  on;

  access_log /home/nginx/domains/pijanitvor.com/log/access.log combined buffer=256k flush=60m;
  error_log /home/nginx/domains/pijanitvor.com/log/error.log;

  root /home/nginx/domains/pijanitvor.com/public;

  location / {
        index index.php index.html index.htm;
        try_files $uri $uri/ /index.php?$uri&$args;
    }

    location /internal_data/ {
        internal;
        allow 127.0.0.1;
        allow MyIP;
        deny all;
    }

    location /library/ {
        internal;
        allow 127.0.0.1;
        allow MyIP;
        deny all;
    }
 
  # prevent access to ./directories and files
        location ~ (?:^|/)\. {
   deny all;
        } 


  include /usr/local/nginx/conf/staticfiles.conf;
  include /usr/local/nginx/conf/php.conf;
  include /usr/local/nginx/conf/drop.conf;
  #include /usr/local/nginx/conf/errorpage.conf;
  include /usr/local/nginx/conf/vts_server.conf;
}

How to insert this into my conf above?

Code:
location ^~ /internal_data/ {
        if ($upstream_http_etag != "") {
            add_header Etag $upstream_http_etag;
        }
        internal;
    }


    location ~ [^/]*\.php$ {
        try_files $fastcgi_script_name =404;
        include fastcgi.conf;
        fastcgi_pass_header Etag;
    }
 
Top Bottom