Current File : /var/www/pediatribu/wp-content/plugins/webp-express/lib/classes/Paths.php
<?php

namespace WebPExpress;

use \WebPExpress\FileHelper;
use \WebPExpress\Multisite;
use \WebPExpress\PathHelper;

class Paths
{
    public static function areAllImageRootsWithinDocRoot() {
        if (!PathHelper::isDocRootAvailable()) {
            return false;
        }

        $roots = self::getImageRootIds();
        foreach ($roots as $dirId) {
            $dir = self::getAbsDirById($dirId);
            if (!PathHelper::canCalculateRelPathFromDocRootToDir($dir)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Check if we can use document root for calculating relative paths (which may not contain "/.." directory traversal)
     *
     * Note that this method allows document root to be outside open_basedir as long as document root is
     * non-empty AND it is possible to calculate relative paths to all image roots (including "index").
     * Here is a case when a relative CAN be calculated:
     * - Document root is configured to "/var/www/website" - which is also the absolute file path.
     * - open_basedir is set to "/var/www/website/wordpress"
     * - uploads is in "/var/www/website/wordpress/wp-content/uploads" (within open_basedir, as it should)
     * - "/wp-uploads" symlinks to "/var/www/website/wordpress")
     * - Wordpress has been configured to use "/wp-uploads" path for uploads.
     *
     * What happens?
     * First, it is tested if the configured upload path ("/wp-uploads") begins with the configured document root ("/var/www/website").
     * This fails.
     * Next, it is tested if the uploads path can be resolved. It can, as it is within the open_basedir.
     * Next, it is tested if the *resolved* the uploads path begins with the configured document root.
     * As "/var/www/website/wordpress/wp-content/uploads" begins with "/var/www/website", we have a match.
     * The relative path can be calculated to be "wordpress/wp-content/uploads".
     * Later, when the relative path is used, it will be used as $docRoot + "/" + $relPath, which
     * will be "/var/www/website/wordpress/wp-content/uploads". All is well.
     *
     * Here is a case where it CAN NOT be calculated:
     * - Document root is configured to "/the-website", which symlinks to "/var/www/website"
     * - open_basedir is set to "/var/www/website/wordpress"
     * - uploads is in "/var/www/website/wordpress/wp-content/uploads" and wordpress is configured to use that upload path.
     *
     * What happens?
     * First, it is tested if the configured upload path begins with the configured document root
     * "/var/www/website/wordpress/wp-content/uploads" does not begin with "/the-website", so it fails.
     * Next, it is tested if the *resolved* the uploads path begins with the configured document root.
     * The resolved uploads path is the same as the configured so it also fails.
     * Next, it is tested if Document root can be resolved. It can not, as the resolved path is not within open_basedir.
     * If it could, it would have been tested if the resolved path begins with the resolved document root and we would have
     * gotten a yes, and the relative path would have been "wordpress/wp-content/uploads" and it would work.
     * However: Document root could not be resolved and we could not get a result.
     * To sum the scenario up:
     * If document root is configured to a symlink which cannot be resolved then it will only be possible to get relative paths
     * when all other configured paths begins are relative to that symlink.
     */
    public static function canUseDocRootForRelPaths() {
        if (!PathHelper::isDocRootAvailable()) {
            return false;
        }
        return self::areAllImageRootsWithinDocRoot();
    }

    public static function canCalculateRelPathFromDocRootToDir($absPath) {
    }

    /**
     * Check if we can use document root for structuring the cache dir.
     *
     * In order to structure the images by doc-root, WebP Express needs all images to be within document root.
     * Does WebP Express in addition to this need to be able to resolve document root?
     * Short answer is yes.
     * The long answer is available as a comment inside ConvertHelperIndependent::getDestination()
     *
     */
    public static function canUseDocRootForStructuringCacheDir() {
        return (PathHelper::isDocRootAvailableAndResolvable() && self::canUseDocRootForRelPaths());
    }

    public static function docRootStatusText()
    {
        if (!PathHelper::isDocRootAvailable()) {
            if (!isset($_SERVER['DOCUMENT_ROOT'])) {
                return 'Unavailable (DOCUMENT_ROOT is not set in the global $_SERVER var)';
            }
            if ($_SERVER['DOCUMENT_ROOT'] == '') {
                return 'Unavailable (empty string)';
            }
            return 'Unavailable';
        }

        $imageRootsWithin = self::canUseDocRootForRelPaths();
        if (!PathHelper::isDocRootAvailableAndResolvable()) {
            $status = 'Available, but either non-existing or not within open_basedir.' .
                ($imageRootsWithin ? '' : ' And not all image roots are within that document root.');
        } elseif (!$imageRootsWithin) {
            $status = 'Available, but not all image roots are within that document root.';
        } else {
            $status = 'Available and its "realpath" is available too.';
        }
        if (self::canUseDocRootForStructuringCacheDir()) {
            $status .= ' Can be used for structuring cache dir.';
        } else {
            $status .= ' Cannot be used for structuring cache dir.';
        }
        return $status;
    }

    public static function getAbsDirId($absDir) {
        switch ($absDir) {
            case self::getContentDirAbs():
                return 'wp-content';
            case self::getIndexDirAbs():
                return 'index';
            case self::getHomeDirAbs():
                return 'home';
            case self::getPluginDirAbs():
                return 'plugins';
            case self::getUploadDirAbs():
                return 'uploads';
            case self::getThemesDirAbs():
                return 'themes';
            case self::getCacheDirAbs():
                return 'cache';
        }
        return false;
    }

    public static function getAbsDirById($dirId) {
        switch ($dirId) {
            case 'wp-content':
                return self::getContentDirAbs();
            case 'index':
                return self::getIndexDirAbs();
            case 'home':
                // "home" is still needed (used in PluginDeactivate.php)
                return self::getHomeDirAbs();
            case 'plugins':
                return self::getPluginDirAbs();
            case 'uploads':
                return self::getUploadDirAbs();
            case 'themes':
                return self::getThemesDirAbs();
            case 'cache':
                return self::getCacheDirAbs();
        }
        return false;
    }

    /**
     * Get ids for folders where SOURCE images may reside
     */
    public static function getImageRootIds() {
        return ['uploads', 'themes', 'plugins', 'wp-content', 'index'];
    }

    /**
     * Find which rootId a path belongs to.
     *
     * Note: If the root ids passed are ordered the way getImageRootIds() returns them, the root id
     * returned will be the "deepest"
     */
    public static function findImageRootOfPath($path, $rootIdsToSearch) {
        foreach ($rootIdsToSearch as $rootId) {
            if (PathHelper::isPathWithinExistingDirPath($path, self::getAbsDirById($rootId))) {
                return $rootId;
            }
        }
        return false;
    }

    public static function getImageRootsDefForSelectedIds($ids) {
        $canUseDocRootForRelPaths = self::canUseDocRootForRelPaths();

        $mapping = [];
        foreach ($ids as $rootId) {
            $obj = [
                'id' => $rootId,
            ];
            $absPath = self::getAbsDirById($rootId);
            if ($canUseDocRootForRelPaths) {
                $obj['rel-path'] = PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed($absPath);
            } else {
                $obj['abs-path'] = $absPath;
            }
            $obj['url'] = self::getUrlById($rootId);
            $mapping[] = $obj;
        }
        return $mapping;
    }

    public static function getImageRootsDef()
    {
        return self::getImageRootsDefForSelectedIds(self::getImageRootIds());
    }

    public static function filterOutSubRoots($rootIds)
    {
        // Get dirs of enabled roots
        $dirs = [];
        foreach ($rootIds as $rootId) {
            $dirs[] = self::getAbsDirById($rootId);
        }

        // Filter out dirs which are below other dirs
        $dirsToSkip = [];
        foreach ($dirs as $dirToExamine) {
            foreach ($dirs as $dirToCompareAgainst) {
                if ($dirToExamine == $dirToCompareAgainst) {
                    continue;
                }
                if (self::isDirInsideDir($dirToExamine, $dirToCompareAgainst)) {
                    $dirsToSkip[] = $dirToExamine;
                    break;
                }
            }
        }
        $dirs = array_diff($dirs, $dirsToSkip);

        // back to ids
        $result = [];
        foreach ($dirs as $dir) {
            $result[] = self::getAbsDirId($dir);
        }
        return $result;
    }

    public static function createDirIfMissing($dir)
    {
        if (!@file_exists($dir)) {
            // We use the wp_mkdir_p, because it takes care of setting folder
            // permissions to that of parent, and handles creating deep structures too
            wp_mkdir_p($dir);
        }
        return file_exists($dir);
    }

    /**
    *  Find out if $dir1 is inside - or equal to - $dir2
    */
    public static function isDirInsideDir($dir1, $dir2)
    {
        $rel = PathHelper::getRelDir($dir2, $dir1);
        return (substr($rel, 0, 3) != '../');
    }

    /**
     *  Return absolute dir.
     *
     *  - Path is canonicalized (without resolving symlinks)
     *  - trailing dash is removed - we don't use that around here.
     *
     *  We do not resolve symlinks anymore. Information was lost that way.
     *  And in some cases we needed the unresolved path - for example in the .htaccess.
     */
    public static function getAbsDir($dir)
    {
        $dir = PathHelper::canonicalize($dir);
        return rtrim($dir, '/');
        /*
        $result = realpath($dir);
        if ($result === false) {
            $dir = PathHelper::canonicalize($dir);
        } else {
            $dir = $result;
        }*/

    }

    // ------------ Home Dir -------------

    // PS: Home dir is not the same as index dir.
    // For example, if Wordpress folder has been moved (method 2), the home dir could be below.
    public static function getHomeDirAbs()
    {
        if (!function_exists('get_home_path')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        return self::getAbsDir(get_home_path());
    }

    // ------------ Index Dir  (WP root dir) -------------
    // (The Wordpress installation dir- where index.php and wp-load.php resides)

    public static function getIndexDirAbs()
    {
        // We used to return self::getAbsDir(ABSPATH), which used realpath.
        // It has been changed now, as it seems we do not need realpath for ABSPATH, as it is defined
        // (in wp-load.php) as dirname(__FILE__) . "/" and according to this link, __FILE__ returns resolved paths:
        // https://stackoverflow.com/questions/3221771/how-do-you-get-php-symlinks-and-file-to-work-together-nicely
        // AND a user reported an open_basedir restriction problem thrown by realpath($_SERVER['DOCUMENT_ROOT']),
        // due to symlinking and opendir restriction (see #322)

        return rtrim(ABSPATH, '/');

        // TODO: read up on this, regarding realpath:
        // https://github.com/twigphp/Twig/issues/2707

    }

    // ------------ .htaccess dir -------------
    // (directory containing the relevant .htaccess)
    // (see https://github.com/rosell-dk/webp-express/issues/36)



    public static function canWriteHTAccessRulesHere($dirName) {
        return FileHelper::canEditOrCreateFileHere($dirName . '/.htaccess');
    }

    public static function canWriteHTAccessRulesInDir($dirId) {
        return self::canWriteHTAccessRulesHere(self::getAbsDirById($dirId));
    }

    public static function returnFirstWritableHTAccessDir($dirs)
    {
        foreach ($dirs as $dir) {
            if (self::canWriteHTAccessRulesHere($dir)) {
                return $dir;
            }
        }
        return false;
    }

    // ------------ Content Dir (the "WP" content dir) -------------

    public static function getContentDirAbs()
    {
        return self::getAbsDir(WP_CONTENT_DIR);
    }
    public static function getContentDirRel()
    {
        return PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(self::getContentDirAbs());
    }
    public static function getContentDirRelToPluginDir()
    {
        return PathHelper::getRelDir(self::getPluginDirAbs(), self::getContentDirAbs());
    }
    public static function getContentDirRelToWebPExpressPluginDir()
    {
        return PathHelper::getRelDir(self::getWebPExpressPluginDirAbs(), self::getContentDirAbs());
    }


    public static function isWPContentDirMoved()
    {
        return (self::getContentDirAbs() != (ABSPATH . 'wp-content'));
    }

    public static function isWPContentDirMovedOutOfAbsPath()
    {
        return !(self::isDirInsideDir(self::getContentDirAbs(), ABSPATH));
    }

    // ------------ Themes Dir -------------

    public static function getThemesDirAbs()
    {
        return self::getContentDirAbs() . '/themes';
    }

    // ------------ WebPExpress Content Dir -------------
    // (the "webp-express" directory inside wp-content)

    public static function getWebPExpressContentDirAbs()
    {
        return self::getContentDirAbs() . '/webp-express';
    }

    public static function getWebPExpressContentDirRel()
    {
        return PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(self::getWebPExpressContentDirAbs());
    }

    public static function createContentDirIfMissing()
    {
        return self::createDirIfMissing(self::getWebPExpressContentDirAbs());
    }

    // ------------ Upload Dir -------------
    public static function getUploadDirAbs()
    {
        $upload_dir = wp_upload_dir(null, false);
        return self::getAbsDir($upload_dir['basedir']);
    }
    public static function getUploadDirRel()
    {
        return PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(self::getUploadDirAbs());
    }

    /*
    public static function getUploadDirAbs()
    {
        if ( defined( 'UPLOADS' ) ) {
            return ABSPATH . rtrim(UPLOADS, '/');
        } else {
            return self::getContentDirAbs() . '/uploads';
        }
    }*/

    public static function isUploadDirMovedOutOfWPContentDir()
    {
        return !(self::isDirInsideDir(self::getUploadDirAbs(), self::getContentDirAbs()));
    }

    public static function isUploadDirMovedOutOfAbsPath()
    {
        return !(self::isDirInsideDir(self::getUploadDirAbs(), ABSPATH));
    }

    // ------------ Config Dir -------------

    public static function getConfigDirAbs()
    {
        return self::getWebPExpressContentDirAbs() . '/config';
    }

    public static function getConfigDirRel()
    {
        return PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(self::getConfigDirAbs());
    }

    public static function createConfigDirIfMissing()
    {
        $configDir = self::getConfigDirAbs();
        // Using code from Wordfence bootstrap.php...
        // Why not simply use wp_mkdir_p ? - it sets the permissions to same as parent. Isn't that better?
        // or perhaps not... - Because we need write permissions in the config dir.
        if (!is_dir($configDir)) {
            @mkdir($configDir, 0775);
            @chmod($configDir, 0775);
            @file_put_contents(rtrim($configDir . '/') . '/.htaccess', <<<APACHE
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
APACHE
            );
            @chmod($configDir . '/.htaccess', 0664);
        }
        return is_dir($configDir);
    }

    public static function getConfigFileName()
    {
        return self::getConfigDirAbs() . '/config.json';
    }

    public static function getWodOptionsFileName()
    {
        return self::getConfigDirAbs() . '/wod-options.json';
    }

    // ------------ Cache Dir -------------

    public static function getCacheDirAbs()
    {
        return self::getWebPExpressContentDirAbs() . '/webp-images';
    }

    public static function getCacheDirRelToDocRoot()
    {
        return PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(self::getCacheDirAbs());
    }

    public static function getCacheDirForImageRoot($destinationFolder, $destinationStructure, $imageRootId)
    {
        if (($destinationFolder == 'mingled') && ($imageRootId == 'uploads')) {
            return self::getUploadDirAbs();
        }

        if ($destinationStructure == 'doc-root') {
            $relPath = PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(
                self::getAbsDirById($imageRootId)
            );
            return self::getCacheDirAbs() . '/doc-root/' . $relPath;
        } else {
            return self::getCacheDirAbs() . '/' . $imageRootId;
        }
    }

    public static function createCacheDirIfMissing()
    {
        return self::createDirIfMissing(self::getCacheDirAbs());
    }

    // ------------ Log Dir -------------

    public static function getLogDirAbs()
    {
        return self::getWebPExpressContentDirAbs() . '/log';
    }

    // ------------ Bigger-than-source  dir -------------

    public static function getBiggerThanSourceDirAbs()
    {
        return self::getWebPExpressContentDirAbs() . '/webp-images-bigger-than-source';
    }

    // ------------ Plugin Dir (all plugins) -------------

    public static function getPluginDirAbs()
    {
        return self::getAbsDir(WP_PLUGIN_DIR);
    }


    public static function isPluginDirMovedOutOfAbsPath()
    {
        return !(self::isDirInsideDir(self::getPluginDirAbs(), ABSPATH));
    }

    public static function isPluginDirMovedOutOfWpContent()
    {
        return !(self::isDirInsideDir(self::getPluginDirAbs(), self::getContentDirAbs()));
    }

    // ------------ WebP Express Plugin Dir -------------

    public static function getWebPExpressPluginDirAbs()
    {
        return self::getAbsDir(WEBPEXPRESS_PLUGIN_DIR);
    }

    // ------------------------------------
    // ---------    Url paths    ----------
    // ------------------------------------

    /**
     *  Get url path (relative to domain) from absolute url.
     *  Ie: "http://example.com/blog" => "blog"
     *  Btw: By "url path" we shall always mean relative to domain
     *       By "url" we shall always mean complete URL (with domain and everything)
     *                                (or at least something that starts with it...)
     *
     *  Also note that in this library, we never returns trailing or leading slashes.
     */
    public static function getUrlPathFromUrl($url)
    {
        $parsed = parse_url($url);
        if (!isset($parsed['path'])) {
            return '';
        }
        if (is_null($parsed['path'])) {
            return '';
        }
        $path = untrailingslashit($parsed['path']);
        return ltrim($path, '/\\');
    }

    public static function getUrlById($dirId) {
        switch ($dirId) {
            case 'wp-content':
                return self::getContentUrl();
            case 'index':
                return self::getHomeUrl();
            case 'home':
                return self::getHomeUrl();
            case 'plugins':
                return self::getPluginsUrl();
            case 'uploads':
                return self::getUploadUrl();
            case 'themes':
                return self::getThemesUrl();
        }
        return false;
    }

    /**
     * Get destination root url and path, provided rootId and some configuration options
     *
     * This method kind of establishes the overall structure of the cache dir.
     * (but not quite, as the logic is also in ConverterHelperIndependent::getDestination).
     *
     * @param  string  $rootId
     * @param  DestinationOptions  $destinationOptions
     *
     * @return array   url and abs-path of destination root
     */
    public static function destinationRoot($rootId, $destinationOptions)
    {
        if (($destinationOptions->mingled) && ($rootId == 'uploads')) {
            return [
                'url' => self::getUrlById('uploads'),
                'abs-path' => self::getUploadDirAbs()
            ];
        } else {

            // Its within these bases:
            $destUrl = self::getUrlById('wp-content') . '/webp-express/webp-images';
            $destPath = self::getAbsDirById('wp-content') . '/webp-express/webp-images';

            if (($destinationOptions->useDocRoot) && self::canUseDocRootForStructuringCacheDir()) {
                $relPathFromDocRootToSourceImageRoot = PathHelper::getRelPathFromDocRootToDirNoDirectoryTraversalAllowed(
                    self::getAbsDirById($rootId)
                );
                return [
                    'url' => $destUrl . '/doc-root/' . $relPathFromDocRootToSourceImageRoot,
                    'abs-path' => $destPath  . '/doc-root/' . $relPathFromDocRootToSourceImageRoot
                ];
            } else {
                $extraPath = '';
                if (is_multisite() && (get_current_blog_id() != 1)) {
                    $extraPath = '/sites/' . get_current_blog_id();   // #510
                }
                return [
                    'url' => $destUrl . '/' . $rootId . $extraPath,
                    'abs-path' => $destPath  . '/' . $rootId . $extraPath
                ];
            }
        }
    }

    public static function getRootAndRelPathForDestination($destinationPath, $imageRoots) {
        foreach ($imageRoots->getArray() as $i => $imageRoot) {
            $rootPath = $imageRoot->getAbsPath();
            if (strpos($destinationPath, realpath($rootPath)) !== false) {
                $relPath = substr($destinationPath, strlen(realpath($rootPath)) + 1);
                return [$imageRoot->id, $relPath];
            }
        }
        return ['', ''];
    }



    // PST:
    // appendOrSetExtension() have been copied from ConvertHelperIndependent.
    // TODO: I should complete the move ASAP.

    /**
     * Append ".webp" to path or replace extension with "webp", depending on what is appropriate.
     *
     * If destination-folder is set to mingled and destination-extension is set to "set" and
     * the path is inside upload folder, the appropriate thing is to SET the extension.
     * Otherwise, it is to APPEND.
     *
     * @param  string  $path
     * @param  string  $destinationFolder
     * @param  string  $destinationExt
     * @param  boolean $inUploadFolder
     */
    public static function appendOrSetExtension($path, $destinationFolder, $destinationExt, $inUploadFolder)
    {
        if (($destinationFolder == 'mingled') && ($destinationExt == 'set') && $inUploadFolder) {
            return preg_replace('/\\.(jpe?g|png)$/i', '', $path) . '.webp';
        } else {
            return $path . '.webp';
        }
    }

    /**
     * Get destination root url and path, provided rootId and some configuration options
     *
     * This method kind of establishes the overall structure of the cache dir.
     * (but not quite, as the logic is also in ConverterHelperIndependent::getDestination).
     *
     * @param  string  $rootId
     * @param  string  $relPath
     * @param  string  $destinationFolder     ("mingled" or "separate")
     * @param  string  $destinationExt        ('append' or 'set')
     * @param  string  $destinationStructure  ("doc-root" or "image-roots")
     *
     * @return array   url and abs-path of destination
     */
   /*
    public static function destinationPath($rootId, $relPath, $destinationFolder, $destinationExt, $destinationStructure) {

        // TODO: Current logic will not do!
        // We must use ConvertHelper::getDestination for the abs path.
        // And we must use logic from AlterHtmlHelper to get the URL
        // Perhaps this method must be abandonned

        $root = self::destinationRoot($rootId, $destinationFolder, $destinationStructure);
        $inUploadFolder = ($rootId == 'upload');
        $relPath = ConvertHelperIndependent::appendOrSetExtension($relPath, $destinationFolder, $destinationExt, $inUploadFolder);

        return [
            'abs-path' => $root['abs-path'] . '/' . $relPath,
            'url' => $root['url'] . '/' . $relPath,
        ];
    }

    public static function destinationPathConvenience($rootId, $relPath, $config) {
        return self::destinationPath(
            $rootId,
            $relPath,
            $config['destination-folder'],
            $config['destination-extension'],
            $config['destination-structure']
        );
    }*/

    public static function getDestinationPathCorrespondingToSource($source, $destinationOptions) {
        return Destination::getDestinationPathCorrespondingToSource(
            $source,
            Paths::getWebPExpressContentDirAbs(),
            Paths::getUploadDirAbs(),
            $destinationOptions,
            new ImageRoots(self::getImageRootsDef())
        );
    }

    public static function getUrlPathById($dirId) {
        return self::getUrlPathFromUrl(self::getUrlById($dirId));
    }

    public static function getHostNameOfUrl($url) {
        $urlComponents = parse_url($url);
        /* ie:
        (
            [scheme] => http
            [host] => we0
            [path] => /wordpress/uploads-moved
        )*/

        if (!isset($urlComponents['host'])) {
            return '';
        } else {
            return $urlComponents['host'];
        }
    }

    // Get complete home url (no trailing slash). Ie: "http://example.com/blog"
    public static function getHomeUrl()
    {
        if (!function_exists('home_url')) {
            // silence is golden?
            // bad joke. Need to handle this...
        }
        return untrailingslashit(home_url());
    }

    /** Get home url, relative to domain. Ie "" or "blog"
     *  If home url is for example http://example.com/blog/, the result is "blog"
     */
    public static function getHomeUrlPath()
    {
        return self::getUrlPathFromUrl(self::getHomeUrl());
    }


    public static function getUploadUrl()
    {
        $uploadDir = wp_upload_dir(null, false);
        return untrailingslashit($uploadDir['baseurl']);
    }

    public static function getUploadUrlPath()
    {
        return self::getUrlPathFromUrl(self::getUploadUrl());
    }

    public static function getContentUrl()
    {
        return untrailingslashit(content_url());
    }

    public static function getContentUrlPath()
    {
        return self::getUrlPathFromUrl(self::getContentUrl());
    }

    public static function getThemesUrl()
    {
        return self::getContentUrl() . '/themes';
    }

    /**
     *  Get Url to plugins (base)
     */
    public static function getPluginsUrl()
    {
        return untrailingslashit(plugins_url());
    }

    /**
     *  Get Url to WebP Express plugin (this is in fact an incomplete URL, you need to append ie '/webp-on-demand.php' to get a full URL)
     */
    public static function getWebPExpressPluginUrl()
    {
        return untrailingslashit(plugins_url('', WEBPEXPRESS_PLUGIN));
    }

    public static function getWebPExpressPluginUrlPath()
    {
        return self::getUrlPathFromUrl(self::getWebPExpressPluginUrl());
    }

    public static function getWodFolderUrlPath()
    {
        return
            self::getWebPExpressPluginUrlPath() .
            '/wod';
    }

    public static function getWod2FolderUrlPath()
    {
        return
            self::getWebPExpressPluginUrlPath() .
            '/wod2';
    }

    public static function getWodUrlPath()
    {
        return
            self::getWodFolderUrlPath() .
            '/webp-on-demand.php';
    }

    public static function getWod2UrlPath()
    {
        return
            self::getWod2FolderUrlPath() .
            '/webp-on-demand.php';
    }

    public static function getWebPRealizerUrlPath()
    {
        return
            self::getWodFolderUrlPath() .
            '/webp-realizer.php';
    }

    public static function getWebPRealizer2UrlPath()
    {
        return
            self::getWod2FolderUrlPath()  .
            '/webp-realizer.php';
    }

    public static function getWebServiceUrl()
    {
        //return self::getWebPExpressPluginUrl() . '/wpc.php';
        //return self::getHomeUrl() . '/webp-express-server';
        return self::getHomeUrl() . '/webp-express-web-service';
    }

    public static function getUrlsAndPathsForTheJavascript()
    {
        return [
            'urls' => [
                'webpExpressRoot' => self::getWebPExpressPluginUrlPath(),
                'content' => self::getContentUrlPath(),
            ],
            'filePaths' => [
                'webpExpressRoot' => self::getWebPExpressPluginDirAbs(),
                'destinationRoot' => self::getCacheDirAbs(),
            ]
        ];
    }

    public static function getSettingsUrl()
    {
        if (!function_exists('admin_url')) {
            require_once ABSPATH . 'wp-includes/link-template.php';
        }
        if (Multisite::isNetworkActivated()) {
            // network_admin_url is also defined in link-template.php.
            return network_admin_url('settings.php?page=webp_express_settings_page');
        } else {
            return admin_url('options-general.php?page=webp_express_settings_page');
        }
    }

}
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!